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("X11DRV_CritSection");
54 unsigned int screen_width
;
55 unsigned int screen_height
;
56 unsigned int screen_depth
;
58 int dxgrab
, usedga
, usexvidmode
;
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] );
222 if (!get_config_key( hkey
, appkey
, "UseXVidMode", buffer
, sizeof(buffer
) ))
223 usexvidmode
= IS_OPTION_TRUE( buffer
[0] );
226 if (!get_config_key( hkey
, appkey
, "ScreenDepth", buffer
, sizeof(buffer
) ))
227 screen_depth
= atoi(buffer
);
229 if (!get_config_key( hkey
, appkey
, "Synchronous", buffer
, sizeof(buffer
) ))
230 synchronous
= IS_OPTION_TRUE( buffer
[0] );
232 if (appkey
) RegCloseKey( appkey
);
237 /***********************************************************************
238 * setup_opengl_visual
240 * Setup the default visual used for OpenGL and Direct3D, and the desktop
241 * window (if it exists). If OpenGL isn't available, the visual is simply
242 * set to the default visual for the display
245 static void setup_opengl_visual( Display
*display
)
247 int err_base
, evt_base
;
249 /* In order to support OpenGL or D3D, we require a double-buffered
251 if (glXQueryExtension(display
, &err_base
, &evt_base
) == True
) {
252 int dblBuf
[]={GLX_RGBA
,GLX_DEPTH_SIZE
,16,GLX_DOUBLEBUFFER
,None
};
255 desktop_vi
= glXChooseVisual(display
, DefaultScreen(display
), dblBuf
);
259 if (desktop_vi
!= NULL
) {
260 visual
= desktop_vi
->visual
;
261 screen
= ScreenOfDisplay(display
, desktop_vi
->screen
);
262 screen_depth
= desktop_vi
->depth
;
265 #endif /* HAVE_OPENGL */
267 /***********************************************************************
268 * X11DRV process initialisation routine
270 static void process_attach(void)
274 get_server_startup();
277 /* setup TSX11 locking */
278 #ifdef NO_REENTRANT_X11
279 old_errno_location
= InterlockedExchangePointer( &wine_errno_location
,
280 x11_errno_location
);
281 old_h_errno_location
= InterlockedExchangePointer( &wine_h_errno_location
,
282 x11_h_errno_location
);
283 #endif /* NO_REENTRANT_X11 */
284 old_tsx11_lock
= wine_tsx11_lock
;
285 old_tsx11_unlock
= wine_tsx11_unlock
;
286 wine_tsx11_lock
= lock_tsx11
;
287 wine_tsx11_unlock
= unlock_tsx11
;
291 if (!(display
= TSXOpenDisplay( NULL
)))
293 MESSAGE( "x11drv: Can't open display: %s\n", XDisplayName(NULL
) );
296 fcntl( ConnectionNumber(display
), F_SETFD
, 1 ); /* set close on exec flag */
297 screen
= DefaultScreenOfDisplay( display
);
298 visual
= DefaultVisual( display
, DefaultScreen(display
) );
299 root_window
= DefaultRootWindow( display
);
301 /* Initialize screen depth */
303 if (screen_depth
) /* depth specified */
306 int *depth_list
= TSXListDepths(display
, DefaultScreen(display
), &depth_count
);
307 for (i
= 0; i
< depth_count
; i
++)
308 if (depth_list
[i
] == screen_depth
) break;
309 TSXFree( depth_list
);
310 if (i
>= depth_count
)
312 MESSAGE( "x11drv: Depth %d not supported on this screen.\n", screen_depth
);
316 else screen_depth
= DefaultDepthOfScreen( screen
);
318 /* If OpenGL is available, change the default visual, etc as necessary */
320 setup_opengl_visual( display
);
321 #endif /* HAVE_OPENGL */
323 /* tell the libX11 that we will do input method handling ourselves
324 * that keep libX11 from doing anything whith dead keys, allowing Wine
325 * to have total control over dead keys, that is this line allows
326 * them to work in Wine, even whith a libX11 including the dead key
327 * patches from Th.Quinot (http://Web.FdN.FR/~tquinot/dead-keys.en.html)
329 TSXOpenIM( display
, NULL
, NULL
, NULL
);
333 XSetErrorHandler( error_handler
);
334 XSynchronize( display
, True
);
337 screen_width
= WidthOfScreen( screen
);
338 screen_height
= HeightOfScreen( screen
);
340 if (desktop_geometry
)
342 Options
.managed
= FALSE
;
343 root_window
= X11DRV_create_desktop( desktop_vi
, desktop_geometry
);
347 if(!X11DRV_GDI_Initialize( display
))
349 ERR( "Couldn't Initialize GDI.\n" );
353 #ifdef HAVE_LIBXXF86VM
354 /* initialize XVidMode */
355 X11DRV_XF86VM_Init();
357 #ifdef HAVE_LIBXXF86DGA2
358 /* initialize DGA2 */
359 X11DRV_XF86DGA2_Init();
363 /*X11DRV_GLX_Init();*/
366 /* load display.dll */
367 LoadLibrary16( "display" );
371 /***********************************************************************
372 * X11DRV thread termination routine
374 static void thread_detach(void)
376 struct x11drv_thread_data
*data
= NtCurrentTeb()->driver_data
;
380 CloseHandle( data
->display_fd
);
382 XCloseDisplay( data
->display
);
384 HeapFree( GetProcessHeap(), 0, data
);
389 /***********************************************************************
390 * X11DRV process termination routine
392 static void process_detach(void)
396 /*X11DRV_GLX_Cleanup();*/
398 #ifdef HAVE_LIBXXF86DGA2
400 X11DRV_XF86DGA2_Cleanup();
402 #ifdef HAVE_LIBXXF86VM
403 /* cleanup XVidMode */
404 X11DRV_XF86VM_Cleanup();
407 /* FIXME: should detach all threads */
411 X11DRV_GDI_Finalize();
413 /* restore TSX11 locking */
414 wine_tsx11_lock
= old_tsx11_lock
;
415 wine_tsx11_unlock
= old_tsx11_unlock
;
416 #ifdef NO_REENTRANT_X11
417 wine_errno_location
= old_errno_location
;
418 wine_h_errno_location
= old_h_errno_location
;
419 #endif /* NO_REENTRANT_X11 */
420 RtlDeleteCriticalSection( &X11DRV_CritSection
);
424 /***********************************************************************
425 * X11DRV thread initialisation routine
427 struct x11drv_thread_data
*x11drv_init_thread_data(void)
429 struct x11drv_thread_data
*data
;
431 if (!(data
= HeapAlloc( GetProcessHeap(), 0, sizeof(*data
) )))
433 ERR( "could not create data\n" );
437 if (!(data
->display
= XOpenDisplay(NULL
)))
440 MESSAGE( "x11drv: Can't open display: %s\n", XDisplayName(NULL
) );
443 fcntl( ConnectionNumber(data
->display
), F_SETFD
, 1 ); /* set close on exec flag */
444 if (synchronous
) XSynchronize( data
->display
, True
);
446 data
->display_fd
= FILE_DupUnixHandle( ConnectionNumber(data
->display
),
447 GENERIC_READ
| SYNCHRONIZE
, FALSE
);
448 data
->process_event_count
= 0;
449 NtCurrentTeb()->driver_data
= data
;
454 /***********************************************************************
455 * X11DRV initialisation routine
457 BOOL WINAPI
X11DRV_Init( HINSTANCE hinst
, DWORD reason
, LPVOID reserved
)
461 case DLL_PROCESS_ATTACH
:
464 case DLL_THREAD_DETACH
:
467 case DLL_PROCESS_DETACH
:
474 /***********************************************************************
475 * GetScreenSaveActive (X11DRV.@)
477 * Returns the active status of the screen saver
479 BOOL
X11DRV_GetScreenSaveActive(void)
482 TSXGetScreenSaver(gdi_display
, &timeout
, &temp
, &temp
, &temp
);
486 /***********************************************************************
487 * SetScreenSaveActive (X11DRV.@)
489 * Activate/Deactivate the screen saver
491 void X11DRV_SetScreenSaveActive(BOOL bActivate
)
493 int timeout
, interval
, prefer_blanking
, allow_exposures
;
494 static int last_timeout
= 15 * 60;
496 TSXGetScreenSaver(gdi_display
, &timeout
, &interval
, &prefer_blanking
,
498 if (timeout
) last_timeout
= timeout
;
500 timeout
= bActivate
? last_timeout
: 0;
501 TSXSetScreenSaver(gdi_display
, timeout
, interval
, prefer_blanking
,