Display thread id instead of %fs in relay trace.
[wine.git] / dlls / x11drv / x11drv_main.c
blob999266a32747763ca456f90d41374081606c3829
1 /*
2 * X11DRV initialization code
4 * Copyright 1998 Patrik Stridvall
5 * Copyright 2000 Alexandre Julliard
6 */
8 #include "config.h"
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. */
13 extern int errno;
14 static int *perrno = &errno;
15 extern int h_errno;
16 static int *ph_errno = &h_errno;
17 #endif /* NO_REENTRANT_X11 */
19 #include <fcntl.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sys/time.h>
24 #include <unistd.h>
25 #include <X11/cursorfont.h>
26 #include "ts_xlib.h"
27 #include "ts_xutil.h"
28 #include "ts_shape.h"
30 #include "winbase.h"
31 #include "wine/winbase16.h"
32 #include "winreg.h"
34 #include "debugtools.h"
35 #include "gdi.h"
36 #include "options.h"
37 #include "user.h"
38 #include "win.h"
39 #include "wine_gl.h"
40 #include "x11drv.h"
41 #include "xvidmode.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;
51 Display *display;
52 Screen *screen;
53 Visual *visual;
54 unsigned int screen_width;
55 unsigned int screen_height;
56 unsigned int screen_depth;
57 Window root_window;
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 /***********************************************************************
69 * x11_errno_location
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 /***********************************************************************
94 * error_handler
96 static int error_handler(Display *display, XErrorEvent *error_evt)
98 DebugBreak(); /* force an entry in the debugger */
99 return 0;
102 /***********************************************************************
103 * lock_tsx11
105 static void lock_tsx11(void)
107 RtlEnterCriticalSection( &X11DRV_CritSection );
110 /***********************************************************************
111 * unlock_tsx11
113 static void unlock_tsx11(void)
115 RtlLeaveCriticalSection( &X11DRV_CritSection );
118 /***********************************************************************
119 * get_server_startup
121 * Get the server startup time
122 * Won't be exact, but should be sufficient
124 static void get_server_startup(void)
126 struct timeval t;
127 gettimeofday( &t, NULL );
128 X11DRV_server_startticks = ((t.tv_sec * 1000) + (t.tv_usec / 1000)) - GetTickCount();
132 /***********************************************************************
133 * get_config_key
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 /***********************************************************************
146 * setup_options
148 * Setup the x11drv options.
150 static void setup_options(void)
152 char buffer[MAX_PATH+16];
153 HKEY hkey, appkey = 0;
154 DWORD count;
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" );
160 ExitProcess(1);
163 /* open the app-specific key */
165 if (GetModuleFileName16( GetCurrentTask(), buffer, MAX_PATH ) ||
166 GetModuleFileNameA( 0, buffer, MAX_PATH ))
168 HKEY tmpkey;
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",
189 buffer + 8 );
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
205 ** sizing entry */
206 if (!IS_OPTION_FALSE(buffer[0])) desktop_geometry = strdup(buffer);
209 screen_depth = 0;
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 );
217 RegCloseKey( hkey );
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;
229 #ifdef HAVE_OPENGL
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
235 * visual */
236 if (glXQueryExtension(display, &err_base, &evt_base) == True) {
237 int dblBuf[]={GLX_RGBA,GLX_DEPTH_SIZE,16,GLX_DOUBLEBUFFER,None};
239 ENTER_GL();
240 desktop_vi = glXChooseVisual(display, DefaultScreen(display), dblBuf);
241 LEAVE_GL();
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 /***********************************************************************
253 * create_desktop
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;
263 XWMHints *wm_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;
273 /* Create window */
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),
288 InputOutput,
289 (desktop_vi == NULL ? CopyFromParent : desktop_vi->visual),
290 CWBackPixel | CWEventMask | CWCursor | (desktop_vi == NULL ? 0 : CWColormap),
291 &win_attr );
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" );
300 ExitProcess(1);
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 );
321 TSXFree( wm_hints );
322 TSXFree( class_hints );
324 /* Map window */
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();
337 setup_options();
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;
351 /* Open display */
353 if (!(display = TSXOpenDisplay( NULL )))
355 MESSAGE( "x11drv: Can't open display: %s\n", XDisplayName(NULL) );
356 ExitProcess(1);
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 */
367 int depth_count, i;
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 );
375 ExitProcess(1);
378 else screen_depth = DefaultDepthOfScreen( screen );
380 /* If OpenGL is available, change the default visual, etc as necessary */
381 #ifdef HAVE_OPENGL
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);
393 if (synchronous)
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 );
408 /* initialize GDI */
409 if(!X11DRV_GDI_Initialize())
411 ERR( "Couldn't Initialize GDI.\n" );
412 ExitProcess(1);
415 /* save keyboard setup */
416 TSXGetKeyboardControl(display, &keyboard_state);
418 /* initialize event handling */
419 X11DRV_EVENT_Init();
421 #ifdef HAVE_LIBXXF86VM
422 /* initialize XVidMode */
423 X11DRV_XF86VM_Init();
424 #endif
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();
451 #endif
453 /* cleanup event handling */
454 X11DRV_EVENT_Cleanup();
456 /* cleanup GDI */
457 X11DRV_GDI_Finalize();
459 /* close the display */
460 XCloseDisplay( display );
461 display = NULL;
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 )
479 switch(reason)
481 case DLL_PROCESS_ATTACH:
482 process_attach();
483 break;
484 case DLL_PROCESS_DETACH:
485 process_detach();
486 break;
488 return TRUE;
491 /***********************************************************************
492 * X11DRV_GetScreenSaveActive
494 * Returns the active status of the screen saver
496 BOOL X11DRV_GetScreenSaveActive(void)
498 int timeout, temp;
499 TSXGetScreenSaver(display, &timeout, &temp, &temp, &temp);
500 return timeout != 0;
503 /***********************************************************************
504 * X11DRV_SetScreenSaveActive
506 * Activate/Deactivate the screen saver
508 void X11DRV_SetScreenSaveActive(BOOL bActivate)
510 if(bActivate)
511 TSXActivateScreenSaver(display);
512 else
513 TSXResetScreenSaver(display);
516 /***********************************************************************
517 * X11DRV_GetScreenSaveTimeout
519 * Return the screen saver timeout
521 int X11DRV_GetScreenSaveTimeout(void)
523 int timeout, temp;
524 TSXGetScreenSaver(display, &timeout, &temp, &temp, &temp);
525 return timeout;
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));