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 #define IS_OPTION_TRUE(ch) \
67 ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1')
68 #define IS_OPTION_FALSE(ch) \
69 ((ch) == 'n' || (ch) == 'N' || (ch) == 'f' || (ch) == 'F' || (ch) == '0')
71 #ifdef NO_REENTRANT_X11
72 static int* (*old_errno_location)(void);
73 static int* (*old_h_errno_location)(void);
75 /***********************************************************************
78 * Get the per-thread errno location.
80 static int *x11_errno_location(void)
82 /* Use static libc errno while running in Xlib. */
83 if (X11DRV_CritSection.OwningThread == GetCurrentThreadId()) return perrno;
84 return old_errno_location();
87 /***********************************************************************
88 * x11_h_errno_location
90 * Get the per-thread h_errno location.
92 static int *x11_h_errno_location(void)
94 /* Use static libc h_errno while running in Xlib. */
95 if (X11DRV_CritSection.OwningThread == GetCurrentThreadId()) return ph_errno;
96 return old_h_errno_location();
98 #endif /* NO_REENTRANT_X11 */
100 /***********************************************************************
103 static int error_handler(Display *display, XErrorEvent *error_evt)
105 DebugBreak(); /* force an entry in the debugger */
109 /***********************************************************************
112 static void lock_tsx11(void)
114 RtlEnterCriticalSection( &X11DRV_CritSection );
117 /***********************************************************************
120 static void unlock_tsx11(void)
122 RtlLeaveCriticalSection( &X11DRV_CritSection );
125 /***********************************************************************
128 * Get the server startup time
129 * Won't be exact, but should be sufficient
131 static void get_server_startup(void)
134 gettimeofday( &t, NULL );
135 X11DRV_server_startticks = ((t.tv_sec * 1000) + (t.tv_usec / 1000)) - GetTickCount();
139 /***********************************************************************
142 * Get a config key from either the app-specific or the default config
144 inline static DWORD get_config_key( HKEY defkey, HKEY appkey, const char *name,
145 char *buffer, DWORD size )
147 if (appkey && !RegQueryValueExA( appkey, name, 0, NULL, buffer, &size )) return 0;
148 return RegQueryValueExA( defkey, name, 0, NULL, buffer, &size );
152 /***********************************************************************
155 * Setup the x11drv options.
157 static void setup_options(void)
159 char buffer[MAX_PATH+16];
160 HKEY hkey, appkey = 0;
163 if (RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\x11drv", 0, NULL,
164 REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL ))
166 ERR("Cannot create config registry key\n" );
170 /* open the app-specific key */
172 if (GetModuleFileName16( GetCurrentTask(), buffer, MAX_PATH ) ||
173 GetModuleFileNameA( 0, buffer, MAX_PATH ))
176 char *p, *appname = buffer;
177 if ((p = strrchr( appname, '/' ))) appname = p + 1;
178 if ((p = strrchr( appname, '\\' ))) appname = p + 1;
179 strcat( appname, "\\x11drv" );
180 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\AppDefaults", &tmpkey ))
182 if (RegOpenKeyA( tmpkey, appname, &appkey )) appkey = 0;
183 RegCloseKey( tmpkey );
187 /* get the display name */
189 strcpy( buffer, "DISPLAY=" );
190 count = sizeof(buffer) - 8;
191 if (!RegQueryValueExA( hkey, "display", 0, NULL, buffer + 8, &count ))
193 const char *display_name = getenv( "DISPLAY" );
194 if (display_name && strcmp( buffer, display_name ))
195 MESSAGE( "x11drv: Warning: $DISPLAY variable ignored, using '%s' specified in config file\n",
197 putenv( strdup(buffer) );
200 /* check --managed option in wine config file if it was not set on command line */
202 if (!Options.managed)
204 if (!get_config_key( hkey, appkey, "Managed", buffer, sizeof(buffer) ))
205 Options.managed = IS_OPTION_TRUE( buffer[0] );
208 if (!get_config_key( hkey, appkey, "Desktop", buffer, sizeof(buffer) ))
210 /* Imperfect validation: If Desktop=N, then we don't turn on
211 ** the --desktop option. We should really validate for a correct
213 if (!IS_OPTION_FALSE(buffer[0])) desktop_geometry = strdup(buffer);
216 if (!get_config_key( hkey, appkey, "DXGrab", buffer, sizeof(buffer) ))
217 dxgrab = IS_OPTION_TRUE( buffer[0] );
219 if (!get_config_key( hkey, appkey, "UseDGA", buffer, sizeof(buffer) ))
220 usedga = IS_OPTION_TRUE( buffer[0] );
223 if (!get_config_key( hkey, appkey, "ScreenDepth", buffer, sizeof(buffer) ))
224 screen_depth = atoi(buffer);
226 if (!get_config_key( hkey, appkey, "Synchronous", buffer, sizeof(buffer) ))
227 synchronous = IS_OPTION_TRUE( buffer[0] );
229 if (appkey) RegCloseKey( appkey );
234 /***********************************************************************
235 * setup_opengl_visual
237 * Setup the default visual used for OpenGL and Direct3D, and the desktop
238 * window (if it exists). If OpenGL isn't available, the visual is simply
239 * set to the default visual for the display
242 static void setup_opengl_visual( Display *display )
244 int err_base, evt_base;
246 /* In order to support OpenGL or D3D, we require a double-buffered
248 if (glXQueryExtension(display, &err_base, &evt_base) == True) {
249 int dblBuf[]={GLX_RGBA,GLX_DEPTH_SIZE,16,GLX_DOUBLEBUFFER,None};
252 desktop_vi = glXChooseVisual(display, DefaultScreen(display), dblBuf);
256 if (desktop_vi != NULL) {
257 visual = desktop_vi->visual;
258 screen = ScreenOfDisplay(display, desktop_vi->screen);
259 screen_depth = desktop_vi->depth;
262 #endif /* HAVE_OPENGL */
264 /***********************************************************************
265 * X11DRV process initialisation routine
267 static void process_attach(void)
271 get_server_startup();
274 /* setup TSX11 locking */
275 #ifdef NO_REENTRANT_X11
276 old_errno_location = (void *)InterlockedExchange( (PLONG)&wine_errno_location,
277 (LONG)x11_errno_location );
278 old_h_errno_location = (void *)InterlockedExchange( (PLONG)&wine_h_errno_location,
279 (LONG)x11_h_errno_location );
280 #endif /* NO_REENTRANT_X11 */
281 old_tsx11_lock = wine_tsx11_lock;
282 old_tsx11_unlock = wine_tsx11_unlock;
283 wine_tsx11_lock = lock_tsx11;
284 wine_tsx11_unlock = unlock_tsx11;
288 if (!(display = TSXOpenDisplay( NULL )))
290 MESSAGE( "x11drv: Can't open display: %s\n", XDisplayName(NULL) );
293 fcntl( ConnectionNumber(display), F_SETFD, 1 ); /* set close on exec flag */
294 screen = DefaultScreenOfDisplay( display );
295 visual = DefaultVisual( display, DefaultScreen(display) );
296 root_window = DefaultRootWindow( display );
298 /* Initialize screen depth */
300 if (screen_depth) /* depth specified */
303 int *depth_list = TSXListDepths(display, DefaultScreen(display), &depth_count);
304 for (i = 0; i < depth_count; i++)
305 if (depth_list[i] == screen_depth) break;
306 TSXFree( depth_list );
307 if (i >= depth_count)
309 MESSAGE( "x11drv: Depth %d not supported on this screen.\n", screen_depth );
313 else screen_depth = DefaultDepthOfScreen( screen );
315 /* If OpenGL is available, change the default visual, etc as necessary */
317 setup_opengl_visual( display );
318 #endif /* HAVE_OPENGL */
320 /* tell the libX11 that we will do input method handling ourselves
321 * that keep libX11 from doing anything whith dead keys, allowing Wine
322 * to have total control over dead keys, that is this line allows
323 * them to work in Wine, even whith a libX11 including the dead key
324 * patches from Th.Quinot (http://Web.FdN.FR/~tquinot/dead-keys.en.html)
326 TSXOpenIM( display, NULL, NULL, NULL);
330 XSetErrorHandler( error_handler );
331 XSynchronize( display, True );
334 screen_width = WidthOfScreen( screen );
335 screen_height = HeightOfScreen( screen );
337 if (desktop_geometry)
339 Options.managed = FALSE;
340 root_window = X11DRV_create_desktop( desktop_vi, desktop_geometry );
344 if(!X11DRV_GDI_Initialize( display ))
346 ERR( "Couldn't Initialize GDI.\n" );
350 #ifdef HAVE_LIBXXF86VM
351 /* initialize XVidMode */
352 X11DRV_XF86VM_Init();
354 #ifdef HAVE_LIBXXF86DGA2
355 /* initialize DGA2 */
356 X11DRV_XF86DGA2_Init();
360 /*X11DRV_GLX_Init();*/
363 /* load display.dll */
364 LoadLibrary16( "display" );
368 /***********************************************************************
369 * X11DRV thread termination routine
371 static void thread_detach(void)
373 struct x11drv_thread_data *data = NtCurrentTeb()->driver_data;
377 CloseHandle( data->display_fd );
379 XCloseDisplay( data->display );
381 HeapFree( GetProcessHeap(), 0, data );
386 /***********************************************************************
387 * X11DRV process termination routine
389 static void process_detach(void)
393 /*X11DRV_GLX_Cleanup();*/
395 #ifdef HAVE_LIBXXF86DGA2
397 X11DRV_XF86DGA2_Cleanup();
399 #ifdef HAVE_LIBXXF86VM
400 /* cleanup XVidMode */
401 X11DRV_XF86VM_Cleanup();
404 /* FIXME: should detach all threads */
408 X11DRV_GDI_Finalize();
410 /* restore TSX11 locking */
411 wine_tsx11_lock = old_tsx11_lock;
412 wine_tsx11_unlock = old_tsx11_unlock;
413 #ifdef NO_REENTRANT_X11
414 wine_errno_location = old_errno_location;
415 wine_h_errno_location = old_h_errno_location;
416 #endif /* NO_REENTRANT_X11 */
417 RtlDeleteCriticalSection( &X11DRV_CritSection );
421 /***********************************************************************
422 * X11DRV thread initialisation routine
424 struct x11drv_thread_data *x11drv_init_thread_data(void)
426 struct x11drv_thread_data *data;
428 if (!(data = HeapAlloc( GetProcessHeap(), 0, sizeof(*data) )))
430 ERR( "could not create data\n" );
434 if (!(data->display = XOpenDisplay(NULL)))
437 MESSAGE( "x11drv: Can't open display: %s\n", XDisplayName(NULL) );
440 fcntl( ConnectionNumber(data->display), F_SETFD, 1 ); /* set close on exec flag */
441 if (synchronous) XSynchronize( data->display, True );
443 data->display_fd = FILE_DupUnixHandle( ConnectionNumber(data->display),
444 GENERIC_READ | SYNCHRONIZE );
445 data->process_event_count = 0;
446 NtCurrentTeb()->driver_data = data;
451 /***********************************************************************
452 * X11DRV initialisation routine
454 BOOL WINAPI X11DRV_Init( HINSTANCE hinst, DWORD reason, LPVOID reserved )
458 case DLL_PROCESS_ATTACH:
461 case DLL_THREAD_DETACH:
464 case DLL_PROCESS_DETACH:
471 /***********************************************************************
472 * GetScreenSaveActive (X11DRV.@)
474 * Returns the active status of the screen saver
476 BOOL X11DRV_GetScreenSaveActive(void)
479 TSXGetScreenSaver(gdi_display, &timeout, &temp, &temp, &temp);
483 /***********************************************************************
484 * SetScreenSaveActive (X11DRV.@)
486 * Activate/Deactivate the screen saver
488 void X11DRV_SetScreenSaveActive(BOOL bActivate)
491 TSXActivateScreenSaver(gdi_display);
493 TSXResetScreenSaver(gdi_display);
496 /***********************************************************************
497 * GetScreenSaveTimeout (X11DRV.@)
499 * Return the screen saver timeout
501 int X11DRV_GetScreenSaveTimeout(void)
504 TSXGetScreenSaver(gdi_display, &timeout, &temp, &temp, &temp);
508 /***********************************************************************
509 * SetScreenSaveTimeout (X11DRV.@)
511 * Set the screen saver timeout
513 void X11DRV_SetScreenSaveTimeout(int nTimeout)
515 /* timeout is a 16bit entity (CARD16) in the protocol, so it should
516 * not get over 32767 or it will get negative. */
517 if (nTimeout>32767) nTimeout = 32767;
518 TSXSetScreenSaver(gdi_display, nTimeout, 60, DefaultBlanking, DefaultExposures);