URLMonikerImpl_BindToStorage: Escape special characters.
[wine/multimedia.git] / dlls / x11drv / x11drv_main.c
blob64ef23cdf5635e8d86c5061881c73868f5eef41f
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, { 0, (DWORD)(__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;
92 static XVisualInfo *desktop_vi;
94 static x11drv_error_callback err_callback; /* current callback for error */
95 static Display *err_callback_display; /* display callback is set for */
96 static void *err_callback_arg; /* error callback argument */
97 static int err_callback_result; /* error callback result */
98 static unsigned long err_serial; /* serial number of first request */
99 static int (*old_error_handler)( Display *, XErrorEvent * );
100 static int use_xim = 1;
101 static char input_style[20];
103 #define IS_OPTION_TRUE(ch) \
104 ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1')
105 #define IS_OPTION_FALSE(ch) \
106 ((ch) == 'n' || (ch) == 'N' || (ch) == 'f' || (ch) == 'F' || (ch) == '0')
108 Atom X11DRV_Atoms[NB_XATOMS - FIRST_XATOM];
110 static const char * const atom_names[NB_XATOMS - FIRST_XATOM] =
112 "CLIPBOARD",
113 "COMPOUND_TEXT",
114 "MULTIPLE",
115 "SELECTION_DATA",
116 "TARGETS",
117 "TEXT",
118 "UTF8_STRING",
119 "RAW_ASCENT",
120 "RAW_DESCENT",
121 "RAW_CAP_HEIGHT",
122 "WM_PROTOCOLS",
123 "WM_DELETE_WINDOW",
124 "WM_TAKE_FOCUS",
125 "KWM_DOCKWINDOW",
126 "DndProtocol",
127 "DndSelection",
128 "_MOTIF_WM_HINTS",
129 "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR",
130 "_NET_WM_MOVERESIZE",
131 "_NET_WM_PID",
132 "_NET_WM_PING",
133 "_NET_WM_NAME",
134 "_NET_WM_WINDOW_TYPE",
135 "_NET_WM_WINDOW_TYPE_UTILITY",
136 "XdndAware",
137 "XdndEnter",
138 "XdndPosition",
139 "XdndStatus",
140 "XdndLeave",
141 "XdndFinished",
142 "XdndDrop",
143 "XdndActionCopy",
144 "XdndActionMove",
145 "XdndActionLink",
146 "XdndActionAsk",
147 "XdndActionPrivate",
148 "XdndSelection",
149 "XdndTarget",
150 "XdndTypeList",
151 "WCF_DIB",
152 "image/gif",
153 "text/html",
154 "text/plain",
155 "text/rtf",
156 "text/richtext"
159 /***********************************************************************
160 * ignore_error
162 * Check if the X error is one we can ignore.
164 static inline BOOL ignore_error( Display *display, XErrorEvent *event )
166 if (event->request_code == X_SetInputFocus && event->error_code == BadMatch) return TRUE;
167 return FALSE;
171 /***********************************************************************
172 * X11DRV_expect_error
174 * Setup a callback function that will be called on an X error. The
175 * callback must return non-zero if the error is the one it expected.
176 * This function acquires the x11 lock; X11DRV_check_error must be
177 * called in all cases to release it.
179 void X11DRV_expect_error( Display *display, x11drv_error_callback callback, void *arg )
181 wine_tsx11_lock();
182 err_callback = callback;
183 err_callback_display = display;
184 err_callback_arg = arg;
185 err_callback_result = 0;
186 err_serial = NextRequest(display);
190 /***********************************************************************
191 * X11DRV_check_error
193 * Check if an expected X11 error occurred; return non-zero if yes.
194 * Also release the x11 lock obtained in X11DRV_expect_error.
195 * The caller is responsible for calling XSync first if necessary.
197 int X11DRV_check_error(void)
199 int ret;
200 err_callback = NULL;
201 ret = err_callback_result;
202 wine_tsx11_unlock();
203 return ret;
207 /***********************************************************************
208 * error_handler
210 static int error_handler( Display *display, XErrorEvent *error_evt )
212 if (err_callback && display == err_callback_display &&
213 (long)(error_evt->serial - err_serial) >= 0)
215 if ((err_callback_result = err_callback( display, error_evt, err_callback_arg )))
217 TRACE( "got expected error %d req %d\n",
218 error_evt->error_code, error_evt->request_code );
219 return 0;
222 if (ignore_error( display, error_evt ))
224 TRACE( "got ignored error %d req %d\n",
225 error_evt->error_code, error_evt->request_code );
226 return 0;
228 if (synchronous)
230 ERR( "X protocol error: serial=%ld, request_code=%d - breaking into debugger\n",
231 error_evt->serial, error_evt->request_code );
232 DebugBreak(); /* force an entry in the debugger */
234 old_error_handler( display, error_evt );
235 return 0;
238 /***********************************************************************
239 * wine_tsx11_lock (X11DRV.@)
241 void wine_tsx11_lock(void)
243 EnterCriticalSection( &X11DRV_CritSection );
246 /***********************************************************************
247 * wine_tsx11_unlock (X11DRV.@)
249 void wine_tsx11_unlock(void)
251 LeaveCriticalSection( &X11DRV_CritSection );
255 /***********************************************************************
256 * get_config_key
258 * Get a config key from either the app-specific or the default config
260 inline static DWORD get_config_key( HKEY defkey, HKEY appkey, const char *name,
261 char *buffer, DWORD size )
263 if (appkey && !RegQueryValueExA( appkey, name, 0, NULL, (LPBYTE)buffer, &size )) return 0;
264 if (defkey && !RegQueryValueExA( defkey, name, 0, NULL, (LPBYTE)buffer, &size )) return 0;
265 return ERROR_FILE_NOT_FOUND;
269 /***********************************************************************
270 * setup_options
272 * Setup the x11drv options.
274 static void setup_options(void)
276 char buffer[MAX_PATH+16];
277 HKEY hkey, appkey = 0;
278 DWORD len;
280 /* @@ Wine registry key: HKCU\Software\Wine\X11 Driver */
281 if (RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\X11 Driver", &hkey )) hkey = 0;
283 /* open the app-specific key */
285 len = (GetModuleFileNameA( 0, buffer, MAX_PATH ));
286 if (len && len < MAX_PATH)
288 HKEY tmpkey;
289 char *p, *appname = buffer;
290 if ((p = strrchr( appname, '/' ))) appname = p + 1;
291 if ((p = strrchr( appname, '\\' ))) appname = p + 1;
292 strcat( appname, "\\X11 Driver" );
293 /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\X11 Driver */
294 if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\AppDefaults", &tmpkey ))
296 if (RegOpenKeyA( tmpkey, appname, &appkey )) appkey = 0;
297 RegCloseKey( tmpkey );
301 if (!get_config_key( hkey, appkey, "Desktop", buffer, sizeof(buffer) ))
303 /* Imperfect validation: If Desktop=N, then we don't turn on
304 ** the --desktop option. We should really validate for a correct
305 ** sizing entry */
306 if (!IS_OPTION_FALSE(buffer[0])) desktop_geometry = strdup(buffer);
309 if (!get_config_key( hkey, appkey, "Managed", buffer, sizeof(buffer) ))
310 managed_mode = IS_OPTION_TRUE( buffer[0] );
312 if (!get_config_key( hkey, appkey, "DXGrab", buffer, sizeof(buffer) ))
313 dxgrab = IS_OPTION_TRUE( buffer[0] );
315 if (!get_config_key( hkey, appkey, "UseDGA", buffer, sizeof(buffer) ))
316 usedga = IS_OPTION_TRUE( buffer[0] );
318 if (!get_config_key( hkey, appkey, "UseXVidMode", buffer, sizeof(buffer) ))
319 usexvidmode = IS_OPTION_TRUE( buffer[0] );
321 if (!get_config_key( hkey, appkey, "UseXRandR", buffer, sizeof(buffer) ))
322 usexrandr = IS_OPTION_TRUE( buffer[0] );
324 if (!get_config_key( hkey, appkey, "UseTakeFocus", buffer, sizeof(buffer) ))
325 use_take_focus = IS_OPTION_TRUE( buffer[0] );
327 if (!get_config_key( hkey, appkey, "UsePrimarySelection", buffer, sizeof(buffer) ))
328 use_primary_selection = IS_OPTION_TRUE( buffer[0] );
330 screen_depth = 0;
331 if (!get_config_key( hkey, appkey, "ScreenDepth", buffer, sizeof(buffer) ))
332 screen_depth = atoi(buffer);
334 if (!get_config_key( hkey, appkey, "Synchronous", buffer, sizeof(buffer) ))
335 synchronous = IS_OPTION_TRUE( buffer[0] );
337 if (!get_config_key( hkey, appkey, "ClientSideWithCore", buffer, sizeof(buffer) ))
338 client_side_with_core = IS_OPTION_TRUE( buffer[0] );
340 if (!get_config_key( hkey, appkey, "ClientSideWithRender", buffer, sizeof(buffer) ))
341 client_side_with_render = IS_OPTION_TRUE( buffer[0] );
343 if (!get_config_key( hkey, appkey, "ClientSideAntiAliasWithCore", buffer, sizeof(buffer) ))
344 client_side_antialias_with_core = IS_OPTION_TRUE( buffer[0] );
346 if (!get_config_key( hkey, appkey, "ClientSideAntiAliasWithRender", buffer, sizeof(buffer) ))
347 client_side_antialias_with_render = IS_OPTION_TRUE( buffer[0] );
349 if (!get_config_key( hkey, appkey, "DesktopDoubleBuffered", buffer, sizeof(buffer) ))
350 desktop_dbl_buf = IS_OPTION_TRUE( buffer[0] );
352 if (!get_config_key( hkey, appkey, "UseXIM", buffer, sizeof(buffer) ))
353 use_xim = IS_OPTION_TRUE( buffer[0] );
355 if (!get_config_key( hkey, appkey, "PrivateColorMap", buffer, sizeof(buffer) ))
356 private_color_map = IS_OPTION_TRUE( buffer[0] );
358 if (!get_config_key( hkey, appkey, "CopyDefaultColors", buffer, sizeof(buffer) ))
359 copy_default_colors = atoi(buffer);
361 if (!get_config_key( hkey, appkey, "AllocSystemColors", buffer, sizeof(buffer) ))
362 alloc_system_colors = atoi(buffer);
364 get_config_key( hkey, appkey, "InputStyle", input_style, sizeof(input_style) );
366 if (appkey) RegCloseKey( appkey );
367 if (hkey) RegCloseKey( hkey );
371 /***********************************************************************
372 * X11DRV process initialisation routine
374 static BOOL process_attach(void)
376 Display *display;
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;
433 #ifdef HAVE_LIBXXF86VM
434 /* initialize XVidMode */
435 X11DRV_XF86VM_Init();
436 #endif
437 #ifdef HAVE_LIBXRANDR
438 /* initialize XRandR */
439 X11DRV_XRandR_Init();
440 #endif
441 #ifdef HAVE_LIBXXF86DGA2
442 /* initialize DGA2 */
443 X11DRV_XF86DGA2_Init();
444 #endif
446 X11DRV_InitKeyboard();
447 X11DRV_InitClipboard();
449 return TRUE;
453 /***********************************************************************
454 * X11DRV thread termination routine
456 static void thread_detach(void)
458 struct x11drv_thread_data *data = TlsGetValue( thread_data_tls_index );
460 if (data)
462 CloseHandle( data->display_fd );
463 wine_tsx11_lock();
464 XCloseDisplay( data->display );
465 /* if (data->xim) XCloseIM( data->xim ); */ /* crashes Xlib */
466 wine_tsx11_unlock();
467 HeapFree( GetProcessHeap(), 0, data );
472 /***********************************************************************
473 * X11DRV process termination routine
475 static void process_detach(void)
477 #ifdef HAVE_LIBXXF86DGA2
478 /* cleanup DGA2 */
479 X11DRV_XF86DGA2_Cleanup();
480 #endif
481 #ifdef HAVE_LIBXXF86VM
482 /* cleanup XVidMode */
483 X11DRV_XF86VM_Cleanup();
484 #endif
485 if(using_client_side_fonts)
486 X11DRV_XRender_Finalize();
488 /* cleanup GDI */
489 X11DRV_GDI_Finalize();
491 DeleteCriticalSection( &X11DRV_CritSection );
492 TlsFree( thread_data_tls_index );
496 /***********************************************************************
497 * X11DRV thread initialisation routine
499 struct x11drv_thread_data *x11drv_init_thread_data(void)
501 struct x11drv_thread_data *data;
503 if (!(data = HeapAlloc( GetProcessHeap(), 0, sizeof(*data) )))
505 ERR( "could not create data\n" );
506 ExitProcess(1);
508 wine_tsx11_lock();
509 if (!(data->display = XOpenDisplay(NULL)))
511 wine_tsx11_unlock();
512 MESSAGE( "x11drv: Can't open display: %s\n", XDisplayName(NULL) );
513 MESSAGE( "Please ensure that your X server is running and that $DISPLAY is set correctly.\n" );
514 ExitProcess(1);
517 fcntl( ConnectionNumber(data->display), F_SETFD, 1 ); /* set close on exec flag */
519 #ifdef HAVE_XKB
520 if (use_xkb)
522 use_xkb = XkbUseExtension( data->display, NULL, NULL );
523 if (use_xkb) XkbSetDetectableAutoRepeat( data->display, True, NULL );
525 #endif
527 if (synchronous) XSynchronize( data->display, True );
528 wine_tsx11_unlock();
530 if (use_xim && !(data->xim = X11DRV_SetupXIM( data->display, input_style )))
531 WARN("Input Method is not available\n");
533 if (wine_server_fd_to_handle( ConnectionNumber(data->display), GENERIC_READ | SYNCHRONIZE,
534 FALSE, &data->display_fd ))
536 MESSAGE( "x11drv: Can't allocate handle for display fd\n" );
537 ExitProcess(1);
539 data->process_event_count = 0;
540 data->cursor = None;
541 data->cursor_window = None;
542 data->grab_window = None;
543 data->last_focus = 0;
544 data->selection_wnd = 0;
545 TlsSetValue( thread_data_tls_index, data );
546 if (desktop_tid) AttachThreadInput( GetCurrentThreadId(), desktop_tid, TRUE );
547 return data;
551 /***********************************************************************
552 * X11DRV initialisation routine
554 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
556 BOOL ret = TRUE;
558 switch(reason)
560 case DLL_PROCESS_ATTACH:
561 ret = process_attach();
562 break;
563 case DLL_THREAD_DETACH:
564 thread_detach();
565 break;
566 case DLL_PROCESS_DETACH:
567 process_detach();
568 break;
570 return ret;
573 /***********************************************************************
574 * GetScreenSaveActive (X11DRV.@)
576 * Returns the active status of the screen saver
578 BOOL X11DRV_GetScreenSaveActive(void)
580 int timeout, temp;
581 wine_tsx11_lock();
582 XGetScreenSaver(gdi_display, &timeout, &temp, &temp, &temp);
583 wine_tsx11_unlock();
584 return timeout != 0;
587 /***********************************************************************
588 * SetScreenSaveActive (X11DRV.@)
590 * Activate/Deactivate the screen saver
592 void X11DRV_SetScreenSaveActive(BOOL bActivate)
594 int timeout, interval, prefer_blanking, allow_exposures;
595 static int last_timeout = 15 * 60;
597 wine_tsx11_lock();
598 XGetScreenSaver(gdi_display, &timeout, &interval, &prefer_blanking,
599 &allow_exposures);
600 if (timeout) last_timeout = timeout;
602 timeout = bActivate ? last_timeout : 0;
603 XSetScreenSaver(gdi_display, timeout, interval, prefer_blanking,
604 allow_exposures);
605 wine_tsx11_unlock();