winex11.drv: Remove desktop double buffering option.
[wine/gsoc_dplay.git] / dlls / winex11.drv / x11drv_main.c
blobf6d241a06ba2b4a0d2c7b99e62b6c5002d0099c7
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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
40 #ifdef HAVE_X11_EXTENSIONS_XRENDER_H
41 #include <X11/extensions/Xrender.h>
42 #endif
44 #include "windef.h"
45 #include "winbase.h"
46 #include "wine/winbase16.h"
47 #include "winreg.h"
49 #include "x11drv.h"
50 #include "xvidmode.h"
51 #include "xrandr.h"
52 #include "wine/server.h"
53 #include "wine/debug.h"
55 WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
56 WINE_DECLARE_DEBUG_CHANNEL(synchronous);
58 static CRITICAL_SECTION X11DRV_CritSection;
59 static CRITICAL_SECTION_DEBUG critsect_debug =
61 0, 0, &X11DRV_CritSection,
62 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
63 0, 0, { (DWORD_PTR)(__FILE__ ": X11DRV_CritSection") }
65 static CRITICAL_SECTION X11DRV_CritSection = { &critsect_debug, -1, 0, 0, 0, 0 };
67 Screen *screen;
68 Visual *visual;
69 unsigned int screen_width;
70 unsigned int screen_height;
71 unsigned int screen_depth;
72 RECT virtual_screen_rect;
73 Window root_window;
74 int dxgrab = 0;
75 int usexvidmode = 1;
76 int usexrandr = 1;
77 int use_xkb = 1;
78 int use_take_focus = 1;
79 int use_primary_selection = 0;
80 int managed_mode = 1;
81 int private_color_map = 0;
82 int primary_monitor = 0;
83 int client_side_with_core = 1;
84 int client_side_with_render = 1;
85 int client_side_antialias_with_core = 1;
86 int client_side_antialias_with_render = 1;
87 int copy_default_colors = 128;
88 int alloc_system_colors = 256;
89 DWORD thread_data_tls_index = TLS_OUT_OF_INDEXES;
90 int xrender_error_base = 0;
92 static x11drv_error_callback err_callback; /* current callback for error */
93 static Display *err_callback_display; /* display callback is set for */
94 static void *err_callback_arg; /* error callback argument */
95 static int err_callback_result; /* error callback result */
96 static unsigned long err_serial; /* serial number of first request */
97 static int (*old_error_handler)( Display *, XErrorEvent * );
98 static int use_xim = 1;
99 static char input_style[20];
101 #define IS_OPTION_TRUE(ch) \
102 ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1')
103 #define IS_OPTION_FALSE(ch) \
104 ((ch) == 'n' || (ch) == 'N' || (ch) == 'f' || (ch) == 'F' || (ch) == '0')
106 Atom X11DRV_Atoms[NB_XATOMS - FIRST_XATOM];
108 static const char * const atom_names[NB_XATOMS - FIRST_XATOM] =
110 "CLIPBOARD",
111 "COMPOUND_TEXT",
112 "MULTIPLE",
113 "SELECTION_DATA",
114 "TARGETS",
115 "TEXT",
116 "UTF8_STRING",
117 "RAW_ASCENT",
118 "RAW_DESCENT",
119 "RAW_CAP_HEIGHT",
120 "WM_PROTOCOLS",
121 "WM_DELETE_WINDOW",
122 "WM_TAKE_FOCUS",
123 "KWM_DOCKWINDOW",
124 "DndProtocol",
125 "DndSelection",
126 "_MOTIF_WM_HINTS",
127 "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR",
128 "_NET_SYSTEM_TRAY_OPCODE",
129 "_NET_SYSTEM_TRAY_S0",
130 "_NET_WM_MOVERESIZE",
131 "_NET_WM_NAME",
132 "_NET_WM_PID",
133 "_NET_WM_PING",
134 "_NET_WM_STATE",
135 "_NET_WM_STATE_FULLSCREEN",
136 "_NET_WM_WINDOW_TYPE",
137 "_NET_WM_WINDOW_TYPE_DIALOG",
138 "_NET_WM_WINDOW_TYPE_NORMAL",
139 "_NET_WM_WINDOW_TYPE_UTILITY",
140 "_XEMBED_INFO",
141 "XdndAware",
142 "XdndEnter",
143 "XdndPosition",
144 "XdndStatus",
145 "XdndLeave",
146 "XdndFinished",
147 "XdndDrop",
148 "XdndActionCopy",
149 "XdndActionMove",
150 "XdndActionLink",
151 "XdndActionAsk",
152 "XdndActionPrivate",
153 "XdndSelection",
154 "XdndTarget",
155 "XdndTypeList",
156 "WCF_DIB",
157 "image/gif",
158 "text/html",
159 "text/plain",
160 "text/rtf",
161 "text/richtext"
164 /***********************************************************************
165 * ignore_error
167 * Check if the X error is one we can ignore.
169 static inline BOOL ignore_error( Display *display, XErrorEvent *event )
171 if (event->request_code == X_SetInputFocus && event->error_code == BadMatch) return TRUE;
173 /* ignore a number of errors on gdi display caused by creating/destroying windows */
174 if (display == gdi_display)
176 if (event->error_code == BadDrawable || event->error_code == BadGC) return TRUE;
177 #ifdef HAVE_X11_EXTENSIONS_XRENDER_H
178 if (xrender_error_base) /* check for XRender errors */
180 if (event->error_code == xrender_error_base + BadPicture) return TRUE;
182 #endif
184 return FALSE;
188 /***********************************************************************
189 * X11DRV_expect_error
191 * Setup a callback function that will be called on an X error. The
192 * callback must return non-zero if the error is the one it expected.
193 * This function acquires the x11 lock; X11DRV_check_error must be
194 * called in all cases to release it.
196 void X11DRV_expect_error( Display *display, x11drv_error_callback callback, void *arg )
198 wine_tsx11_lock();
199 err_callback = callback;
200 err_callback_display = display;
201 err_callback_arg = arg;
202 err_callback_result = 0;
203 err_serial = NextRequest(display);
207 /***********************************************************************
208 * X11DRV_check_error
210 * Check if an expected X11 error occurred; return non-zero if yes.
211 * Also release the x11 lock obtained in X11DRV_expect_error.
212 * The caller is responsible for calling XSync first if necessary.
214 int X11DRV_check_error(void)
216 int ret;
217 err_callback = NULL;
218 ret = err_callback_result;
219 wine_tsx11_unlock();
220 return ret;
224 /***********************************************************************
225 * error_handler
227 static int error_handler( Display *display, XErrorEvent *error_evt )
229 if (err_callback && display == err_callback_display &&
230 (long)(error_evt->serial - err_serial) >= 0)
232 if ((err_callback_result = err_callback( display, error_evt, err_callback_arg )))
234 TRACE( "got expected error %d req %d\n",
235 error_evt->error_code, error_evt->request_code );
236 return 0;
239 if (ignore_error( display, error_evt ))
241 TRACE( "got ignored error %d req %d\n",
242 error_evt->error_code, error_evt->request_code );
243 return 0;
245 if (TRACE_ON(synchronous))
247 ERR( "X protocol error: serial=%ld, request_code=%d - breaking into debugger\n",
248 error_evt->serial, error_evt->request_code );
249 DebugBreak(); /* force an entry in the debugger */
251 old_error_handler( display, error_evt );
252 return 0;
255 /***********************************************************************
256 * wine_tsx11_lock (X11DRV.@)
258 void wine_tsx11_lock(void)
260 EnterCriticalSection( &X11DRV_CritSection );
263 /***********************************************************************
264 * wine_tsx11_unlock (X11DRV.@)
266 void wine_tsx11_unlock(void)
268 LeaveCriticalSection( &X11DRV_CritSection );
272 /***********************************************************************
273 * get_config_key
275 * Get a config key from either the app-specific or the default config
277 inline static DWORD get_config_key( HKEY defkey, HKEY appkey, const char *name,
278 char *buffer, DWORD size )
280 if (appkey && !RegQueryValueExA( appkey, name, 0, NULL, (LPBYTE)buffer, &size )) return 0;
281 if (defkey && !RegQueryValueExA( defkey, name, 0, NULL, (LPBYTE)buffer, &size )) return 0;
282 return ERROR_FILE_NOT_FOUND;
286 /***********************************************************************
287 * setup_options
289 * Setup the x11drv options.
291 static void setup_options(void)
293 char buffer[MAX_PATH+16];
294 HKEY hkey, appkey = 0;
295 DWORD len;
297 /* @@ Wine registry key: HKCU\Software\Wine\X11 Driver */
298 if (RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\X11 Driver", &hkey )) hkey = 0;
300 /* open the app-specific key */
302 len = (GetModuleFileNameA( 0, buffer, MAX_PATH ));
303 if (len && len < MAX_PATH)
305 HKEY tmpkey;
306 char *p, *appname = buffer;
307 if ((p = strrchr( appname, '/' ))) appname = p + 1;
308 if ((p = strrchr( appname, '\\' ))) appname = p + 1;
309 strcat( appname, "\\X11 Driver" );
310 /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\X11 Driver */
311 if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\AppDefaults", &tmpkey ))
313 if (RegOpenKeyA( tmpkey, appname, &appkey )) appkey = 0;
314 RegCloseKey( tmpkey );
318 if (!get_config_key( hkey, appkey, "Managed", buffer, sizeof(buffer) ))
319 managed_mode = IS_OPTION_TRUE( buffer[0] );
321 if (!get_config_key( hkey, appkey, "DXGrab", buffer, sizeof(buffer) ))
322 dxgrab = IS_OPTION_TRUE( buffer[0] );
324 if (!get_config_key( hkey, appkey, "UseXVidMode", buffer, sizeof(buffer) ))
325 usexvidmode = IS_OPTION_TRUE( buffer[0] );
327 if (!get_config_key( hkey, appkey, "UseXRandR", buffer, sizeof(buffer) ))
328 usexrandr = IS_OPTION_TRUE( buffer[0] );
330 if (!get_config_key( hkey, appkey, "UseTakeFocus", buffer, sizeof(buffer) ))
331 use_take_focus = IS_OPTION_TRUE( buffer[0] );
333 if (!get_config_key( hkey, appkey, "UsePrimarySelection", buffer, sizeof(buffer) ))
334 use_primary_selection = IS_OPTION_TRUE( buffer[0] );
336 screen_depth = 0;
337 if (!get_config_key( hkey, appkey, "ScreenDepth", buffer, sizeof(buffer) ))
338 screen_depth = atoi(buffer);
340 if (!get_config_key( hkey, appkey, "ClientSideWithCore", buffer, sizeof(buffer) ))
341 client_side_with_core = IS_OPTION_TRUE( buffer[0] );
343 if (!get_config_key( hkey, appkey, "ClientSideWithRender", buffer, sizeof(buffer) ))
344 client_side_with_render = IS_OPTION_TRUE( buffer[0] );
346 if (!get_config_key( hkey, appkey, "ClientSideAntiAliasWithCore", buffer, sizeof(buffer) ))
347 client_side_antialias_with_core = IS_OPTION_TRUE( buffer[0] );
349 if (!get_config_key( hkey, appkey, "ClientSideAntiAliasWithRender", buffer, sizeof(buffer) ))
350 client_side_antialias_with_render = 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, "PrimaryMonitor", buffer, sizeof(buffer) ))
359 primary_monitor = atoi( buffer );
361 if (!get_config_key( hkey, appkey, "CopyDefaultColors", buffer, sizeof(buffer) ))
362 copy_default_colors = atoi(buffer);
364 if (!get_config_key( hkey, appkey, "AllocSystemColors", buffer, sizeof(buffer) ))
365 alloc_system_colors = atoi(buffer);
367 get_config_key( hkey, appkey, "InputStyle", input_style, sizeof(input_style) );
369 if (appkey) RegCloseKey( appkey );
370 if (hkey) RegCloseKey( hkey );
374 /***********************************************************************
375 * X11DRV process initialisation routine
377 static BOOL process_attach(void)
379 Display *display;
380 XVisualInfo *desktop_vi = NULL;
382 setup_options();
384 if ((thread_data_tls_index = TlsAlloc()) == TLS_OUT_OF_INDEXES) return FALSE;
386 /* Open display */
388 if (!XInitThreads()) ERR( "XInitThreads failed, trouble ahead\n" );
390 if (!(display = XOpenDisplay( NULL ))) return FALSE;
392 fcntl( ConnectionNumber(display), F_SETFD, 1 ); /* set close on exec flag */
393 screen = DefaultScreenOfDisplay( display );
394 visual = DefaultVisual( display, DefaultScreen(display) );
395 root_window = DefaultRootWindow( display );
396 gdi_display = display;
397 old_error_handler = XSetErrorHandler( error_handler );
399 /* Initialize screen depth */
401 if (screen_depth) /* depth specified */
403 int depth_count, i;
404 int *depth_list = XListDepths(display, DefaultScreen(display), &depth_count);
405 for (i = 0; i < depth_count; i++)
406 if (depth_list[i] == screen_depth) break;
407 XFree( depth_list );
408 if (i >= depth_count)
410 WARN( "invalid depth %d, using default\n", screen_depth );
411 screen_depth = 0;
414 if (!screen_depth) screen_depth = DefaultDepthOfScreen( screen );
416 /* If OpenGL is available, change the default visual, etc as necessary */
417 if ((desktop_vi = X11DRV_setup_opengl_visual( display )))
419 visual = desktop_vi->visual;
420 screen = ScreenOfDisplay(display, desktop_vi->screen);
421 screen_depth = desktop_vi->depth;
422 XFree(desktop_vi);
425 XInternAtoms( display, (char **)atom_names, NB_XATOMS - FIRST_XATOM, False, X11DRV_Atoms );
427 if (TRACE_ON(synchronous)) XSynchronize( display, True );
429 screen_width = WidthOfScreen( screen );
430 screen_height = HeightOfScreen( screen );
432 xinerama_init();
433 X11DRV_Settings_Init();
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
444 X11DRV_InitKeyboard();
445 X11DRV_InitClipboard();
447 return TRUE;
451 /***********************************************************************
452 * X11DRV thread termination routine
454 static void thread_detach(void)
456 struct x11drv_thread_data *data = TlsGetValue( thread_data_tls_index );
458 if (data)
460 X11DRV_ResetSelectionOwner();
461 CloseHandle( data->display_fd );
462 wine_tsx11_lock();
463 if (data->xim) XCloseIM( data->xim );
464 XCloseDisplay( data->display );
465 wine_tsx11_unlock();
466 HeapFree( GetProcessHeap(), 0, data );
471 /***********************************************************************
472 * X11DRV process termination routine
474 static void process_detach(void)
476 #ifdef HAVE_LIBXXF86VM
477 /* cleanup XVidMode */
478 X11DRV_XF86VM_Cleanup();
479 #endif
480 if(using_client_side_fonts)
481 X11DRV_XRender_Finalize();
483 /* cleanup GDI */
484 X11DRV_GDI_Finalize();
486 DeleteCriticalSection( &X11DRV_CritSection );
487 TlsFree( thread_data_tls_index );
491 /***********************************************************************
492 * X11DRV thread initialisation routine
494 struct x11drv_thread_data *x11drv_init_thread_data(void)
496 struct x11drv_thread_data *data;
498 if (!(data = HeapAlloc( GetProcessHeap(), 0, sizeof(*data) )))
500 ERR( "could not create data\n" );
501 ExitProcess(1);
503 wine_tsx11_lock();
504 if (!(data->display = XOpenDisplay(NULL)))
506 wine_tsx11_unlock();
507 MESSAGE( "x11drv: Can't open display: %s\n", XDisplayName(NULL) );
508 MESSAGE( "Please ensure that your X server is running and that $DISPLAY is set correctly.\n" );
509 ExitProcess(1);
512 fcntl( ConnectionNumber(data->display), F_SETFD, 1 ); /* set close on exec flag */
514 #ifdef HAVE_XKB
515 if (use_xkb)
517 use_xkb = XkbUseExtension( data->display, NULL, NULL );
518 if (use_xkb)
520 /* Hack: dummy call to XkbKeysymToModifiers to force initialisation of Xkb internals */
521 /* This works around an Xlib bug where it tries to get the display lock */
522 /* twice during XFilterEvents if Xkb hasn't been initialised yet. */
523 XkbKeysymToModifiers( data->display, 'A' );
524 XkbSetDetectableAutoRepeat( data->display, True, NULL );
527 #endif
529 if (TRACE_ON(synchronous)) XSynchronize( data->display, True );
530 wine_tsx11_unlock();
532 if (!use_xim)
533 data->xim = NULL;
534 else if (!(data->xim = X11DRV_SetupXIM( data->display, input_style )))
535 WARN("Input Method is not available\n");
537 if (wine_server_fd_to_handle( ConnectionNumber(data->display), GENERIC_READ | SYNCHRONIZE,
538 0, &data->display_fd ))
540 MESSAGE( "x11drv: Can't allocate handle for display fd\n" );
541 ExitProcess(1);
543 data->process_event_count = 0;
544 data->cursor = None;
545 data->cursor_window = None;
546 data->grab_window = None;
547 data->last_focus = 0;
548 data->selection_wnd = 0;
549 TlsSetValue( thread_data_tls_index, data );
550 return data;
554 /***********************************************************************
555 * X11DRV initialisation routine
557 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
559 BOOL ret = TRUE;
561 switch(reason)
563 case DLL_PROCESS_ATTACH:
564 ret = process_attach();
565 break;
566 case DLL_THREAD_DETACH:
567 thread_detach();
568 break;
569 case DLL_PROCESS_DETACH:
570 process_detach();
571 break;
573 return ret;
576 /***********************************************************************
577 * GetScreenSaveActive (X11DRV.@)
579 * Returns the active status of the screen saver
581 BOOL X11DRV_GetScreenSaveActive(void)
583 int timeout, temp;
584 wine_tsx11_lock();
585 XGetScreenSaver(gdi_display, &timeout, &temp, &temp, &temp);
586 wine_tsx11_unlock();
587 return timeout != 0;
590 /***********************************************************************
591 * SetScreenSaveActive (X11DRV.@)
593 * Activate/Deactivate the screen saver
595 void X11DRV_SetScreenSaveActive(BOOL bActivate)
597 int timeout, interval, prefer_blanking, allow_exposures;
598 static int last_timeout = 15 * 60;
600 wine_tsx11_lock();
601 XGetScreenSaver(gdi_display, &timeout, &interval, &prefer_blanking,
602 &allow_exposures);
603 if (timeout) last_timeout = timeout;
605 timeout = bActivate ? last_timeout : 0;
606 XSetScreenSaver(gdi_display, timeout, interval, prefer_blanking,
607 allow_exposures);
608 wine_tsx11_unlock();