wined3d: Prevent crash in setup_light.
[wine.git] / dlls / x11drv / x11drv_main.c
blob5c1069048253a2f80333db7cf2660fc18e6e148b
1 /*
2 * X11DRV initialization code
4 * Copyright 1998 Patrik Stridvall
5 * Copyright 2000 Alexandre Julliard
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "config.h"
24 #include <fcntl.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #ifdef HAVE_SYS_TIME_H
30 # include <sys/time.h>
31 #endif
32 #ifdef HAVE_UNISTD_H
33 # include <unistd.h>
34 #endif
35 #include <X11/cursorfont.h>
36 #include <X11/Xlib.h>
37 #ifdef HAVE_XKB
38 #include <X11/XKBlib.h>
39 #endif
41 #include "windef.h"
42 #include "winbase.h"
43 #include "wine/winbase16.h"
44 #include "winreg.h"
46 #include "x11drv.h"
47 #include "xvidmode.h"
48 #include "xrandr.h"
49 #include "dga2.h"
50 #include "wine/server.h"
51 #include "wine/debug.h"
53 WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
55 static CRITICAL_SECTION X11DRV_CritSection;
56 static CRITICAL_SECTION_DEBUG critsect_debug =
58 0, 0, &X11DRV_CritSection,
59 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
60 0, 0, { (DWORD_PTR)(__FILE__ ": X11DRV_CritSection") }
62 static CRITICAL_SECTION X11DRV_CritSection = { &critsect_debug, -1, 0, 0, 0, 0 };
64 Screen *screen;
65 Visual *visual;
66 unsigned int screen_width;
67 unsigned int screen_height;
68 unsigned int screen_depth;
69 Window root_window;
70 DWORD desktop_tid = 0;
71 int dxgrab = 0;
72 int usedga = 0;
73 int usexvidmode = 0;
74 int usexrandr = 1;
75 int use_xkb = 1;
76 int use_take_focus = 1;
77 int use_primary_selection = 0;
78 int managed_mode = 1;
79 int private_color_map = 0;
80 int client_side_with_core = 1;
81 int client_side_with_render = 1;
82 int client_side_antialias_with_core = 1;
83 int client_side_antialias_with_render = 1;
84 int using_wine_desktop = 0;
85 int copy_default_colors = 128;
86 int alloc_system_colors = 256;
87 DWORD thread_data_tls_index = TLS_OUT_OF_INDEXES;
89 static BOOL synchronous; /* run in synchronous mode? */
90 static BOOL desktop_dbl_buf = TRUE;
91 static char *desktop_geometry;
93 static x11drv_error_callback err_callback; /* current callback for error */
94 static Display *err_callback_display; /* display callback is set for */
95 static void *err_callback_arg; /* error callback argument */
96 static int err_callback_result; /* error callback result */
97 static unsigned long err_serial; /* serial number of first request */
98 static int (*old_error_handler)( Display *, XErrorEvent * );
99 static int use_xim = 1;
100 static char input_style[20];
102 #define IS_OPTION_TRUE(ch) \
103 ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1')
104 #define IS_OPTION_FALSE(ch) \
105 ((ch) == 'n' || (ch) == 'N' || (ch) == 'f' || (ch) == 'F' || (ch) == '0')
107 Atom X11DRV_Atoms[NB_XATOMS - FIRST_XATOM];
109 static const char * const atom_names[NB_XATOMS - FIRST_XATOM] =
111 "CLIPBOARD",
112 "COMPOUND_TEXT",
113 "MULTIPLE",
114 "SELECTION_DATA",
115 "TARGETS",
116 "TEXT",
117 "UTF8_STRING",
118 "RAW_ASCENT",
119 "RAW_DESCENT",
120 "RAW_CAP_HEIGHT",
121 "WM_PROTOCOLS",
122 "WM_DELETE_WINDOW",
123 "WM_TAKE_FOCUS",
124 "KWM_DOCKWINDOW",
125 "DndProtocol",
126 "DndSelection",
127 "_MOTIF_WM_HINTS",
128 "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR",
129 "_NET_WM_MOVERESIZE",
130 "_NET_WM_PID",
131 "_NET_WM_PING",
132 "_NET_WM_NAME",
133 "_NET_WM_WINDOW_TYPE",
134 "_NET_WM_WINDOW_TYPE_UTILITY",
135 "XdndAware",
136 "XdndEnter",
137 "XdndPosition",
138 "XdndStatus",
139 "XdndLeave",
140 "XdndFinished",
141 "XdndDrop",
142 "XdndActionCopy",
143 "XdndActionMove",
144 "XdndActionLink",
145 "XdndActionAsk",
146 "XdndActionPrivate",
147 "XdndSelection",
148 "XdndTarget",
149 "XdndTypeList",
150 "WCF_DIB",
151 "image/gif",
152 "text/html",
153 "text/plain",
154 "text/rtf",
155 "text/richtext"
158 /***********************************************************************
159 * ignore_error
161 * Check if the X error is one we can ignore.
163 static inline BOOL ignore_error( Display *display, XErrorEvent *event )
165 if (event->request_code == X_SetInputFocus && event->error_code == BadMatch) return TRUE;
166 return FALSE;
170 /***********************************************************************
171 * X11DRV_expect_error
173 * Setup a callback function that will be called on an X error. The
174 * callback must return non-zero if the error is the one it expected.
175 * This function acquires the x11 lock; X11DRV_check_error must be
176 * called in all cases to release it.
178 void X11DRV_expect_error( Display *display, x11drv_error_callback callback, void *arg )
180 wine_tsx11_lock();
181 err_callback = callback;
182 err_callback_display = display;
183 err_callback_arg = arg;
184 err_callback_result = 0;
185 err_serial = NextRequest(display);
189 /***********************************************************************
190 * X11DRV_check_error
192 * Check if an expected X11 error occurred; return non-zero if yes.
193 * Also release the x11 lock obtained in X11DRV_expect_error.
194 * The caller is responsible for calling XSync first if necessary.
196 int X11DRV_check_error(void)
198 int ret;
199 err_callback = NULL;
200 ret = err_callback_result;
201 wine_tsx11_unlock();
202 return ret;
206 /***********************************************************************
207 * error_handler
209 static int error_handler( Display *display, XErrorEvent *error_evt )
211 if (err_callback && display == err_callback_display &&
212 (long)(error_evt->serial - err_serial) >= 0)
214 if ((err_callback_result = err_callback( display, error_evt, err_callback_arg )))
216 TRACE( "got expected error %d req %d\n",
217 error_evt->error_code, error_evt->request_code );
218 return 0;
221 if (ignore_error( display, error_evt ))
223 TRACE( "got ignored error %d req %d\n",
224 error_evt->error_code, error_evt->request_code );
225 return 0;
227 if (synchronous)
229 ERR( "X protocol error: serial=%ld, request_code=%d - breaking into debugger\n",
230 error_evt->serial, error_evt->request_code );
231 DebugBreak(); /* force an entry in the debugger */
233 old_error_handler( display, error_evt );
234 return 0;
237 /***********************************************************************
238 * wine_tsx11_lock (X11DRV.@)
240 void wine_tsx11_lock(void)
242 EnterCriticalSection( &X11DRV_CritSection );
245 /***********************************************************************
246 * wine_tsx11_unlock (X11DRV.@)
248 void wine_tsx11_unlock(void)
250 LeaveCriticalSection( &X11DRV_CritSection );
254 /***********************************************************************
255 * get_config_key
257 * Get a config key from either the app-specific or the default config
259 inline static DWORD get_config_key( HKEY defkey, HKEY appkey, const char *name,
260 char *buffer, DWORD size )
262 if (appkey && !RegQueryValueExA( appkey, name, 0, NULL, (LPBYTE)buffer, &size )) return 0;
263 if (defkey && !RegQueryValueExA( defkey, name, 0, NULL, (LPBYTE)buffer, &size )) return 0;
264 return ERROR_FILE_NOT_FOUND;
268 /***********************************************************************
269 * setup_options
271 * Setup the x11drv options.
273 static void setup_options(void)
275 char buffer[MAX_PATH+16];
276 HKEY hkey, appkey = 0;
277 DWORD len;
279 /* @@ Wine registry key: HKCU\Software\Wine\X11 Driver */
280 if (RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\X11 Driver", &hkey )) hkey = 0;
282 /* open the app-specific key */
284 len = (GetModuleFileNameA( 0, buffer, MAX_PATH ));
285 if (len && len < MAX_PATH)
287 HKEY tmpkey;
288 char *p, *appname = buffer;
289 if ((p = strrchr( appname, '/' ))) appname = p + 1;
290 if ((p = strrchr( appname, '\\' ))) appname = p + 1;
291 strcat( appname, "\\X11 Driver" );
292 /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\X11 Driver */
293 if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\AppDefaults", &tmpkey ))
295 if (RegOpenKeyA( tmpkey, appname, &appkey )) appkey = 0;
296 RegCloseKey( tmpkey );
300 if (!get_config_key( hkey, appkey, "Desktop", buffer, sizeof(buffer) ))
302 /* Imperfect validation: If Desktop=N, then we don't turn on
303 ** the --desktop option. We should really validate for a correct
304 ** sizing entry */
305 if (!IS_OPTION_FALSE(buffer[0])) desktop_geometry = strdup(buffer);
308 if (!get_config_key( hkey, appkey, "Managed", buffer, sizeof(buffer) ))
309 managed_mode = IS_OPTION_TRUE( buffer[0] );
311 if (!get_config_key( hkey, appkey, "DXGrab", buffer, sizeof(buffer) ))
312 dxgrab = IS_OPTION_TRUE( buffer[0] );
314 if (!get_config_key( hkey, appkey, "UseDGA", buffer, sizeof(buffer) ))
315 usedga = IS_OPTION_TRUE( buffer[0] );
317 if (!get_config_key( hkey, appkey, "UseXVidMode", buffer, sizeof(buffer) ))
318 usexvidmode = IS_OPTION_TRUE( buffer[0] );
320 if (!get_config_key( hkey, appkey, "UseXRandR", buffer, sizeof(buffer) ))
321 usexrandr = IS_OPTION_TRUE( buffer[0] );
323 if (!get_config_key( hkey, appkey, "UseTakeFocus", buffer, sizeof(buffer) ))
324 use_take_focus = IS_OPTION_TRUE( buffer[0] );
326 if (!get_config_key( hkey, appkey, "UsePrimarySelection", buffer, sizeof(buffer) ))
327 use_primary_selection = IS_OPTION_TRUE( buffer[0] );
329 screen_depth = 0;
330 if (!get_config_key( hkey, appkey, "ScreenDepth", buffer, sizeof(buffer) ))
331 screen_depth = atoi(buffer);
333 if (!get_config_key( hkey, appkey, "Synchronous", buffer, sizeof(buffer) ))
334 synchronous = IS_OPTION_TRUE( buffer[0] );
336 if (!get_config_key( hkey, appkey, "ClientSideWithCore", buffer, sizeof(buffer) ))
337 client_side_with_core = IS_OPTION_TRUE( buffer[0] );
339 if (!get_config_key( hkey, appkey, "ClientSideWithRender", buffer, sizeof(buffer) ))
340 client_side_with_render = IS_OPTION_TRUE( buffer[0] );
342 if (!get_config_key( hkey, appkey, "ClientSideAntiAliasWithCore", buffer, sizeof(buffer) ))
343 client_side_antialias_with_core = IS_OPTION_TRUE( buffer[0] );
345 if (!get_config_key( hkey, appkey, "ClientSideAntiAliasWithRender", buffer, sizeof(buffer) ))
346 client_side_antialias_with_render = IS_OPTION_TRUE( buffer[0] );
348 if (!get_config_key( hkey, appkey, "DesktopDoubleBuffered", buffer, sizeof(buffer) ))
349 desktop_dbl_buf = IS_OPTION_TRUE( buffer[0] );
351 if (!get_config_key( hkey, appkey, "UseXIM", buffer, sizeof(buffer) ))
352 use_xim = IS_OPTION_TRUE( buffer[0] );
354 if (!get_config_key( hkey, appkey, "PrivateColorMap", buffer, sizeof(buffer) ))
355 private_color_map = IS_OPTION_TRUE( buffer[0] );
357 if (!get_config_key( hkey, appkey, "CopyDefaultColors", buffer, sizeof(buffer) ))
358 copy_default_colors = atoi(buffer);
360 if (!get_config_key( hkey, appkey, "AllocSystemColors", buffer, sizeof(buffer) ))
361 alloc_system_colors = atoi(buffer);
363 get_config_key( hkey, appkey, "InputStyle", input_style, sizeof(input_style) );
365 if (appkey) RegCloseKey( appkey );
366 if (hkey) RegCloseKey( hkey );
370 /***********************************************************************
371 * X11DRV process initialisation routine
373 static BOOL process_attach(void)
375 Display *display;
376 XVisualInfo *desktop_vi = NULL;
378 setup_options();
380 if ((thread_data_tls_index = TlsAlloc()) == TLS_OUT_OF_INDEXES) return FALSE;
382 /* Open display */
384 if (!(display = XOpenDisplay( NULL ))) return FALSE;
386 fcntl( ConnectionNumber(display), F_SETFD, 1 ); /* set close on exec flag */
387 screen = DefaultScreenOfDisplay( display );
388 visual = DefaultVisual( display, DefaultScreen(display) );
389 root_window = DefaultRootWindow( display );
390 gdi_display = display;
391 old_error_handler = XSetErrorHandler( error_handler );
393 /* Initialize screen depth */
395 if (screen_depth) /* depth specified */
397 int depth_count, i;
398 int *depth_list = XListDepths(display, DefaultScreen(display), &depth_count);
399 for (i = 0; i < depth_count; i++)
400 if (depth_list[i] == screen_depth) break;
401 XFree( depth_list );
402 if (i >= depth_count)
404 WARN( "invalid depth %d, using default\n", screen_depth );
405 screen_depth = 0;
408 if (!screen_depth) screen_depth = DefaultDepthOfScreen( screen );
410 /* If OpenGL is available, change the default visual, etc as necessary */
411 if (desktop_dbl_buf && (desktop_vi = X11DRV_setup_opengl_visual( display )))
413 visual = desktop_vi->visual;
414 screen = ScreenOfDisplay(display, desktop_vi->screen);
415 screen_depth = desktop_vi->depth;
418 XInternAtoms( display, (char **)atom_names, NB_XATOMS - FIRST_XATOM, False, X11DRV_Atoms );
420 if (synchronous) XSynchronize( display, True );
422 screen_width = WidthOfScreen( screen );
423 screen_height = HeightOfScreen( screen );
425 X11DRV_Settings_Init();
427 if (desktop_geometry)
429 root_window = X11DRV_create_desktop( desktop_vi, desktop_geometry );
430 using_wine_desktop = 1;
432 if(desktop_vi)
433 XFree(desktop_vi);
435 #ifdef HAVE_LIBXXF86VM
436 /* initialize XVidMode */
437 X11DRV_XF86VM_Init();
438 #endif
439 #ifdef HAVE_LIBXRANDR
440 /* initialize XRandR */
441 X11DRV_XRandR_Init();
442 #endif
443 #ifdef HAVE_LIBXXF86DGA2
444 /* initialize DGA2 */
445 X11DRV_XF86DGA2_Init();
446 #endif
448 X11DRV_InitKeyboard();
449 X11DRV_InitClipboard();
451 return TRUE;
455 /***********************************************************************
456 * X11DRV thread termination routine
458 static void thread_detach(void)
460 struct x11drv_thread_data *data = TlsGetValue( thread_data_tls_index );
462 if (data)
464 CloseHandle( data->display_fd );
465 wine_tsx11_lock();
466 XCloseDisplay( data->display );
467 /* if (data->xim) XCloseIM( data->xim ); */ /* crashes Xlib */
468 wine_tsx11_unlock();
469 HeapFree( GetProcessHeap(), 0, data );
474 /***********************************************************************
475 * X11DRV process termination routine
477 static void process_detach(void)
479 #ifdef HAVE_LIBXXF86DGA2
480 /* cleanup DGA2 */
481 X11DRV_XF86DGA2_Cleanup();
482 #endif
483 #ifdef HAVE_LIBXXF86VM
484 /* cleanup XVidMode */
485 X11DRV_XF86VM_Cleanup();
486 #endif
487 if(using_client_side_fonts)
488 X11DRV_XRender_Finalize();
490 /* cleanup GDI */
491 X11DRV_GDI_Finalize();
493 DeleteCriticalSection( &X11DRV_CritSection );
494 TlsFree( thread_data_tls_index );
498 /***********************************************************************
499 * X11DRV thread initialisation routine
501 struct x11drv_thread_data *x11drv_init_thread_data(void)
503 struct x11drv_thread_data *data;
505 if (!(data = HeapAlloc( GetProcessHeap(), 0, sizeof(*data) )))
507 ERR( "could not create data\n" );
508 ExitProcess(1);
510 wine_tsx11_lock();
511 if (!(data->display = XOpenDisplay(NULL)))
513 wine_tsx11_unlock();
514 MESSAGE( "x11drv: Can't open display: %s\n", XDisplayName(NULL) );
515 MESSAGE( "Please ensure that your X server is running and that $DISPLAY is set correctly.\n" );
516 ExitProcess(1);
519 fcntl( ConnectionNumber(data->display), F_SETFD, 1 ); /* set close on exec flag */
521 #ifdef HAVE_XKB
522 if (use_xkb)
524 use_xkb = XkbUseExtension( data->display, NULL, NULL );
525 if (use_xkb) XkbSetDetectableAutoRepeat( data->display, True, NULL );
527 #endif
529 if (synchronous) XSynchronize( data->display, True );
530 wine_tsx11_unlock();
532 if (use_xim && !(data->xim = X11DRV_SetupXIM( data->display, input_style )))
533 WARN("Input Method is not available\n");
535 if (wine_server_fd_to_handle( ConnectionNumber(data->display), GENERIC_READ | SYNCHRONIZE,
536 0, &data->display_fd ))
538 MESSAGE( "x11drv: Can't allocate handle for display fd\n" );
539 ExitProcess(1);
541 data->process_event_count = 0;
542 data->cursor = None;
543 data->cursor_window = None;
544 data->grab_window = None;
545 data->last_focus = 0;
546 data->selection_wnd = 0;
547 TlsSetValue( thread_data_tls_index, data );
548 if (desktop_tid) AttachThreadInput( GetCurrentThreadId(), desktop_tid, TRUE );
549 return data;
553 /***********************************************************************
554 * X11DRV initialisation routine
556 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
558 BOOL ret = TRUE;
560 switch(reason)
562 case DLL_PROCESS_ATTACH:
563 ret = process_attach();
564 break;
565 case DLL_THREAD_DETACH:
566 thread_detach();
567 break;
568 case DLL_PROCESS_DETACH:
569 process_detach();
570 break;
572 return ret;
575 /***********************************************************************
576 * GetScreenSaveActive (X11DRV.@)
578 * Returns the active status of the screen saver
580 BOOL X11DRV_GetScreenSaveActive(void)
582 int timeout, temp;
583 wine_tsx11_lock();
584 XGetScreenSaver(gdi_display, &timeout, &temp, &temp, &temp);
585 wine_tsx11_unlock();
586 return timeout != 0;
589 /***********************************************************************
590 * SetScreenSaveActive (X11DRV.@)
592 * Activate/Deactivate the screen saver
594 void X11DRV_SetScreenSaveActive(BOOL bActivate)
596 int timeout, interval, prefer_blanking, allow_exposures;
597 static int last_timeout = 15 * 60;
599 wine_tsx11_lock();
600 XGetScreenSaver(gdi_display, &timeout, &interval, &prefer_blanking,
601 &allow_exposures);
602 if (timeout) last_timeout = timeout;
604 timeout = bActivate ? last_timeout : 0;
605 XSetScreenSaver(gdi_display, timeout, interval, prefer_blanking,
606 allow_exposures);
607 wine_tsx11_unlock();