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"
43 DEFAULT_DEBUG_CHANNEL(x11drv
);
45 static XKeyboardState keyboard_state
;
46 static void (*old_tsx11_lock
)(void);
47 static void (*old_tsx11_unlock
)(void);
49 static CRITICAL_SECTION X11DRV_CritSection
= CRITICAL_SECTION_INIT
;
54 unsigned int screen_width
;
55 unsigned int screen_height
;
56 unsigned int screen_depth
;
59 unsigned int X11DRV_server_startticks
;
61 static BOOL synchronous
; /* run in synchronous mode? */
62 static char *desktop_geometry
;
64 #ifdef NO_REENTRANT_X11
65 static int* (*old_errno_location
)(void);
66 static int* (*old_h_errno_location
)(void);
68 /***********************************************************************
71 * Get the per-thread errno location.
73 static int *x11_errno_location(void)
75 /* Use static libc errno while running in Xlib. */
76 if (X11DRV_CritSection
.OwningThread
== GetCurrentThreadId()) return perrno
;
77 return old_errno_location();
80 /***********************************************************************
81 * x11_h_errno_location
83 * Get the per-thread h_errno location.
85 static int *x11_h_errno_location(void)
87 /* Use static libc h_errno while running in Xlib. */
88 if (X11DRV_CritSection
.OwningThread
== GetCurrentThreadId()) return ph_errno
;
89 return old_h_errno_location();
91 #endif /* NO_REENTRANT_X11 */
93 /***********************************************************************
96 static int error_handler(Display
*display
, XErrorEvent
*error_evt
)
98 DebugBreak(); /* force an entry in the debugger */
102 /***********************************************************************
105 static void lock_tsx11(void)
107 RtlEnterCriticalSection( &X11DRV_CritSection
);
110 /***********************************************************************
113 static void unlock_tsx11(void)
115 RtlLeaveCriticalSection( &X11DRV_CritSection
);
118 /***********************************************************************
121 * Get the server startup time
122 * Won't be exact, but should be sufficient
124 static void get_server_startup(void)
127 gettimeofday( &t
, NULL
);
128 X11DRV_server_startticks
= ((t
.tv_sec
* 1000) + (t
.tv_usec
/ 1000)) - GetTickCount();
132 /***********************************************************************
135 * Get a config key from either the app-specific or the default config
137 inline static DWORD
get_config_key( HKEY defkey
, HKEY appkey
, const char *name
,
138 char *buffer
, DWORD size
)
140 if (appkey
&& !RegQueryValueExA( appkey
, name
, 0, NULL
, buffer
, &size
)) return 0;
141 return RegQueryValueExA( defkey
, name
, 0, NULL
, buffer
, &size
);
145 /***********************************************************************
148 * Setup the x11drv options.
150 static void setup_options(void)
152 char buffer
[MAX_PATH
+16];
153 HKEY hkey
, appkey
= 0;
156 if (RegCreateKeyExA( HKEY_LOCAL_MACHINE
, "Software\\Wine\\Wine\\Config\\x11drv", 0, NULL
,
157 REG_OPTION_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hkey
, NULL
))
159 ERR("Cannot create config registry key\n" );
163 /* open the app-specific key */
165 if (GetModuleFileName16( GetCurrentTask(), buffer
, MAX_PATH
) ||
166 GetModuleFileNameA( 0, buffer
, MAX_PATH
))
169 char *p
, *appname
= buffer
;
170 if ((p
= strrchr( appname
, '/' ))) appname
= p
+ 1;
171 if ((p
= strrchr( appname
, '\\' ))) appname
= p
+ 1;
172 strcat( appname
, "\\x11drv" );
173 if (!RegOpenKeyA( HKEY_LOCAL_MACHINE
, "Software\\Wine\\Wine\\Config\\AppDefaults", &tmpkey
))
175 if (RegOpenKeyA( tmpkey
, appname
, &appkey
)) appkey
= 0;
176 RegCloseKey( tmpkey
);
180 /* get the display name */
182 strcpy( buffer
, "DISPLAY=" );
183 count
= sizeof(buffer
) - 8;
184 if (!RegQueryValueExA( hkey
, "display", 0, NULL
, buffer
+ 8, &count
))
186 const char *display_name
= getenv( "DISPLAY" );
187 if (display_name
&& strcmp( buffer
, display_name
))
188 MESSAGE( "x11drv: Warning: $DISPLAY variable ignored, using '%s' specified in config file\n",
190 putenv( strdup(buffer
) );
193 /* check --managed option in wine config file if it was not set on command line */
195 if (!Options
.managed
)
197 if (!get_config_key( hkey
, appkey
, "Managed", buffer
, sizeof(buffer
) ))
198 Options
.managed
= IS_OPTION_TRUE( buffer
[0] );
201 if (!get_config_key( hkey
, appkey
, "Desktop", buffer
, sizeof(buffer
) ))
203 /* Imperfect validation: If Desktop=N, then we don't turn on
204 ** the --desktop option. We should really validate for a correct
206 if (!IS_OPTION_FALSE(buffer
[0])) desktop_geometry
= strdup(buffer
);
210 if (!get_config_key( hkey
, appkey
, "ScreenDepth", buffer
, sizeof(buffer
) ))
211 screen_depth
= atoi(buffer
);
213 if (!get_config_key( hkey
, appkey
, "Synchronous", buffer
, sizeof(buffer
) ))
214 synchronous
= IS_OPTION_TRUE( buffer
[0] );
216 if (appkey
) RegCloseKey( appkey
);
221 /***********************************************************************
222 * setup_opengl_visual
224 * Setup the default visual used for OpenGL and Direct3D, and the desktop
225 * window (if it exists). If OpenGL isn't available, the visual is simply
226 * set to the default visual for the display
228 XVisualInfo
*desktop_vi
= NULL
;
230 static void setup_opengl_visual( void )
232 int err_base
, evt_base
;
234 /* In order to support OpenGL or D3D, we require a double-buffered
236 if (glXQueryExtension(display
, &err_base
, &evt_base
) == True
) {
237 int dblBuf
[]={GLX_RGBA
,GLX_DEPTH_SIZE
,16,GLX_DOUBLEBUFFER
,None
};
240 desktop_vi
= glXChooseVisual(display
, DefaultScreen(display
), dblBuf
);
244 if (desktop_vi
!= NULL
) {
245 visual
= desktop_vi
->visual
;
246 screen
= ScreenOfDisplay(display
, desktop_vi
->screen
);
247 screen_depth
= desktop_vi
->depth
;
250 #endif /* HAVE_OPENGL */
252 /***********************************************************************
255 * Create the desktop window for the --desktop mode.
257 static void create_desktop( const char *geometry
)
259 int x
= 0, y
= 0, flags
;
260 unsigned int width
= 640, height
= 480; /* Default size = 640x480 */
261 char *name
= "Wine desktop";
262 XSizeHints
*size_hints
;
264 XClassHint
*class_hints
;
265 XSetWindowAttributes win_attr
;
266 XTextProperty window_name
;
267 Atom XA_WM_DELETE_WINDOW
;
269 flags
= TSXParseGeometry( geometry
, &x
, &y
, &width
, &height
);
270 screen_width
= width
;
271 screen_height
= height
;
274 win_attr
.background_pixel
= BlackPixel(display
, 0);
275 win_attr
.event_mask
= ExposureMask
| KeyPressMask
| KeyReleaseMask
|
276 PointerMotionMask
| ButtonPressMask
|
277 ButtonReleaseMask
| EnterWindowMask
;
278 win_attr
.cursor
= TSXCreateFontCursor( display
, XC_top_left_arrow
);
280 if (desktop_vi
!= NULL
) {
281 win_attr
.colormap
= XCreateColormap(display
, RootWindow(display
,desktop_vi
->screen
),
282 desktop_vi
->visual
, AllocNone
);
284 root_window
= TSXCreateWindow( display
,
285 (desktop_vi
== NULL
? DefaultRootWindow(display
) : RootWindow(display
, desktop_vi
->screen
)),
286 x
, y
, width
, height
, 0,
287 (desktop_vi
== NULL
? CopyFromParent
: desktop_vi
->depth
),
289 (desktop_vi
== NULL
? CopyFromParent
: desktop_vi
->visual
),
290 CWBackPixel
| CWEventMask
| CWCursor
| (desktop_vi
== NULL
? 0 : CWColormap
),
293 /* Set window manager properties */
294 size_hints
= TSXAllocSizeHints();
295 wm_hints
= TSXAllocWMHints();
296 class_hints
= TSXAllocClassHint();
297 if (!size_hints
|| !wm_hints
|| !class_hints
)
299 MESSAGE("Not enough memory for window manager hints.\n" );
302 size_hints
->min_width
= size_hints
->max_width
= width
;
303 size_hints
->min_height
= size_hints
->max_height
= height
;
304 size_hints
->flags
= PMinSize
| PMaxSize
;
305 if (flags
& (XValue
| YValue
)) size_hints
->flags
|= USPosition
;
306 if (flags
& (WidthValue
| HeightValue
)) size_hints
->flags
|= USSize
;
307 else size_hints
->flags
|= PSize
;
309 wm_hints
->flags
= InputHint
| StateHint
;
310 wm_hints
->input
= True
;
311 wm_hints
->initial_state
= NormalState
;
312 class_hints
->res_name
= "wine";
313 class_hints
->res_class
= "Wine";
315 TSXStringListToTextProperty( &name
, 1, &window_name
);
316 TSXSetWMProperties( display
, root_window
, &window_name
, &window_name
,
317 NULL
, 0, size_hints
, wm_hints
, class_hints
);
318 XA_WM_DELETE_WINDOW
= TSXInternAtom( display
, "WM_DELETE_WINDOW", False
);
319 TSXSetWMProtocols( display
, root_window
, &XA_WM_DELETE_WINDOW
, 1 );
320 TSXFree( size_hints
);
322 TSXFree( class_hints
);
325 TSXMapWindow( display
, root_window
);
329 /***********************************************************************
330 * X11DRV process initialisation routine
332 static void process_attach(void)
334 WND_Driver
= &X11DRV_WND_Driver
;
336 get_server_startup();
339 /* setup TSX11 locking */
340 #ifdef NO_REENTRANT_X11
341 old_errno_location
= (void *)InterlockedExchange( (PLONG
)&wine_errno_location
,
342 (LONG
)x11_errno_location
);
343 old_h_errno_location
= (void *)InterlockedExchange( (PLONG
)&wine_h_errno_location
,
344 (LONG
)x11_h_errno_location
);
345 #endif /* NO_REENTRANT_X11 */
346 old_tsx11_lock
= wine_tsx11_lock
;
347 old_tsx11_unlock
= wine_tsx11_unlock
;
348 wine_tsx11_lock
= lock_tsx11
;
349 wine_tsx11_unlock
= unlock_tsx11
;
353 if (!(display
= TSXOpenDisplay( NULL
)))
355 MESSAGE( "x11drv: Can't open display: %s\n", XDisplayName(NULL
) );
358 fcntl( ConnectionNumber(display
), F_SETFD
, 1 ); /* set close on exec flag */
359 screen
= DefaultScreenOfDisplay( display
);
360 visual
= DefaultVisual( display
, DefaultScreen(display
) );
361 root_window
= DefaultRootWindow( display
);
363 /* Initialize screen depth */
365 if (screen_depth
) /* depth specified */
368 int *depth_list
= TSXListDepths(display
, DefaultScreen(display
), &depth_count
);
369 for (i
= 0; i
< depth_count
; i
++)
370 if (depth_list
[i
] == screen_depth
) break;
371 TSXFree( depth_list
);
372 if (i
>= depth_count
)
374 MESSAGE( "x11drv: Depth %d not supported on this screen.\n", screen_depth
);
378 else screen_depth
= DefaultDepthOfScreen( screen
);
380 /* If OpenGL is available, change the default visual, etc as necessary */
382 setup_opengl_visual();
383 #endif /* HAVE_OPENGL */
385 /* tell the libX11 that we will do input method handling ourselves
386 * that keep libX11 from doing anything whith dead keys, allowing Wine
387 * to have total control over dead keys, that is this line allows
388 * them to work in Wine, even whith a libX11 including the dead key
389 * patches from Th.Quinot (http://Web.FdN.FR/~tquinot/dead-keys.en.html)
391 TSXOpenIM( display
, NULL
, NULL
, NULL
);
395 XSetErrorHandler( error_handler
);
396 XSynchronize( display
, True
);
399 screen_width
= WidthOfScreen( screen
);
400 screen_height
= HeightOfScreen( screen
);
402 if (desktop_geometry
)
404 Options
.managed
= FALSE
;
405 create_desktop( desktop_geometry
);
409 if(!X11DRV_GDI_Initialize())
411 ERR( "Couldn't Initialize GDI.\n" );
415 /* save keyboard setup */
416 TSXGetKeyboardControl(display
, &keyboard_state
);
418 /* initialize event handling */
421 #ifdef HAVE_LIBXXF86VM
422 /* initialize XVidMode */
423 X11DRV_XF86VM_Init();
426 /* load display.dll */
427 LoadLibrary16( "display" );
431 /***********************************************************************
432 * X11DRV process termination routine
434 static void process_detach(void)
436 /* restore keyboard setup */
437 XKeyboardControl keyboard_value
;
439 keyboard_value
.key_click_percent
= keyboard_state
.key_click_percent
;
440 keyboard_value
.bell_percent
= keyboard_state
.bell_percent
;
441 keyboard_value
.bell_pitch
= keyboard_state
.bell_pitch
;
442 keyboard_value
.bell_duration
= keyboard_state
.bell_duration
;
443 keyboard_value
.auto_repeat_mode
= keyboard_state
.global_auto_repeat
;
445 TSXChangeKeyboardControl(display
, KBKeyClickPercent
| KBBellPercent
|
446 KBBellPitch
| KBBellDuration
| KBAutoRepeatMode
, &keyboard_value
);
448 #ifdef HAVE_LIBXXF86VM
449 /* cleanup XVidMode */
450 X11DRV_XF86VM_Cleanup();
453 /* cleanup event handling */
454 X11DRV_EVENT_Cleanup();
457 X11DRV_GDI_Finalize();
459 /* close the display */
460 XCloseDisplay( display
);
463 /* restore TSX11 locking */
464 wine_tsx11_lock
= old_tsx11_lock
;
465 wine_tsx11_unlock
= old_tsx11_unlock
;
466 #ifdef NO_REENTRANT_X11
467 wine_errno_location
= old_errno_location
;
468 wine_h_errno_location
= old_h_errno_location
;
469 #endif /* NO_REENTRANT_X11 */
470 RtlDeleteCriticalSection( &X11DRV_CritSection
);
474 /***********************************************************************
475 * X11DRV initialisation routine
477 BOOL WINAPI
X11DRV_Init( HINSTANCE hinst
, DWORD reason
, LPVOID reserved
)
481 case DLL_PROCESS_ATTACH
:
484 case DLL_PROCESS_DETACH
:
491 /***********************************************************************
492 * X11DRV_GetScreenSaveActive
494 * Returns the active status of the screen saver
496 BOOL
X11DRV_GetScreenSaveActive(void)
499 TSXGetScreenSaver(display
, &timeout
, &temp
, &temp
, &temp
);
503 /***********************************************************************
504 * X11DRV_SetScreenSaveActive
506 * Activate/Deactivate the screen saver
508 void X11DRV_SetScreenSaveActive(BOOL bActivate
)
511 TSXActivateScreenSaver(display
);
513 TSXResetScreenSaver(display
);
516 /***********************************************************************
517 * X11DRV_GetScreenSaveTimeout
519 * Return the screen saver timeout
521 int X11DRV_GetScreenSaveTimeout(void)
524 TSXGetScreenSaver(display
, &timeout
, &temp
, &temp
, &temp
);
528 /***********************************************************************
529 * X11DRV_SetScreenSaveTimeout
531 * Set the screen saver timeout
533 void X11DRV_SetScreenSaveTimeout(int nTimeout
)
535 /* timeout is a 16bit entity (CARD16) in the protocol, so it should
536 * not get over 32767 or it will get negative. */
537 if (nTimeout
>32767) nTimeout
= 32767;
538 TSXSetScreenSaver(display
, nTimeout
, 60, DefaultBlanking
, DefaultExposures
);
541 /***********************************************************************
542 * X11DRV_IsSingleWindow
544 BOOL
X11DRV_IsSingleWindow(void)
546 return (root_window
!= DefaultRootWindow(display
));