winex11.drv: Added better support for the X file drag protocol.
[wine/wine64.git] / dlls / winex11.drv / x11drv_main.c
blobe4c8a879bdc912faf7e0489031b556a8dbcf24aa
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",
162 "text/uri-list"
165 /***********************************************************************
166 * ignore_error
168 * Check if the X error is one we can ignore.
170 static inline BOOL ignore_error( Display *display, XErrorEvent *event )
172 if (event->request_code == X_SetInputFocus && event->error_code == BadMatch) return TRUE;
174 /* ignore a number of errors on gdi display caused by creating/destroying windows */
175 if (display == gdi_display)
177 if (event->error_code == BadDrawable || event->error_code == BadGC) return TRUE;
178 #ifdef HAVE_X11_EXTENSIONS_XRENDER_H
179 if (xrender_error_base) /* check for XRender errors */
181 if (event->error_code == xrender_error_base + BadPicture) return TRUE;
183 #endif
185 return FALSE;
189 /***********************************************************************
190 * X11DRV_expect_error
192 * Setup a callback function that will be called on an X error. The
193 * callback must return non-zero if the error is the one it expected.
194 * This function acquires the x11 lock; X11DRV_check_error must be
195 * called in all cases to release it.
197 void X11DRV_expect_error( Display *display, x11drv_error_callback callback, void *arg )
199 wine_tsx11_lock();
200 err_callback = callback;
201 err_callback_display = display;
202 err_callback_arg = arg;
203 err_callback_result = 0;
204 err_serial = NextRequest(display);
208 /***********************************************************************
209 * X11DRV_check_error
211 * Check if an expected X11 error occurred; return non-zero if yes.
212 * Also release the x11 lock obtained in X11DRV_expect_error.
213 * The caller is responsible for calling XSync first if necessary.
215 int X11DRV_check_error(void)
217 int ret;
218 err_callback = NULL;
219 ret = err_callback_result;
220 wine_tsx11_unlock();
221 return ret;
225 /***********************************************************************
226 * error_handler
228 static int error_handler( Display *display, XErrorEvent *error_evt )
230 if (err_callback && display == err_callback_display &&
231 (long)(error_evt->serial - err_serial) >= 0)
233 if ((err_callback_result = err_callback( display, error_evt, err_callback_arg )))
235 TRACE( "got expected error %d req %d\n",
236 error_evt->error_code, error_evt->request_code );
237 return 0;
240 if (ignore_error( display, error_evt ))
242 TRACE( "got ignored error %d req %d\n",
243 error_evt->error_code, error_evt->request_code );
244 return 0;
246 if (TRACE_ON(synchronous))
248 ERR( "X protocol error: serial=%ld, request_code=%d - breaking into debugger\n",
249 error_evt->serial, error_evt->request_code );
250 DebugBreak(); /* force an entry in the debugger */
252 old_error_handler( display, error_evt );
253 return 0;
256 /***********************************************************************
257 * wine_tsx11_lock (X11DRV.@)
259 void wine_tsx11_lock(void)
261 EnterCriticalSection( &X11DRV_CritSection );
264 /***********************************************************************
265 * wine_tsx11_unlock (X11DRV.@)
267 void wine_tsx11_unlock(void)
269 LeaveCriticalSection( &X11DRV_CritSection );
273 /***********************************************************************
274 * get_config_key
276 * Get a config key from either the app-specific or the default config
278 static inline DWORD get_config_key( HKEY defkey, HKEY appkey, const char *name,
279 char *buffer, DWORD size )
281 if (appkey && !RegQueryValueExA( appkey, name, 0, NULL, (LPBYTE)buffer, &size )) return 0;
282 if (defkey && !RegQueryValueExA( defkey, name, 0, NULL, (LPBYTE)buffer, &size )) return 0;
283 return ERROR_FILE_NOT_FOUND;
287 /***********************************************************************
288 * setup_options
290 * Setup the x11drv options.
292 static void setup_options(void)
294 char buffer[MAX_PATH+16];
295 HKEY hkey, appkey = 0;
296 DWORD len;
298 /* @@ Wine registry key: HKCU\Software\Wine\X11 Driver */
299 if (RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\X11 Driver", &hkey )) hkey = 0;
301 /* open the app-specific key */
303 len = (GetModuleFileNameA( 0, buffer, MAX_PATH ));
304 if (len && len < MAX_PATH)
306 HKEY tmpkey;
307 char *p, *appname = buffer;
308 if ((p = strrchr( appname, '/' ))) appname = p + 1;
309 if ((p = strrchr( appname, '\\' ))) appname = p + 1;
310 strcat( appname, "\\X11 Driver" );
311 /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\X11 Driver */
312 if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\AppDefaults", &tmpkey ))
314 if (RegOpenKeyA( tmpkey, appname, &appkey )) appkey = 0;
315 RegCloseKey( tmpkey );
319 if (!get_config_key( hkey, appkey, "Managed", buffer, sizeof(buffer) ))
320 managed_mode = IS_OPTION_TRUE( buffer[0] );
322 if (!get_config_key( hkey, appkey, "DXGrab", buffer, sizeof(buffer) ))
323 dxgrab = IS_OPTION_TRUE( buffer[0] );
325 if (!get_config_key( hkey, appkey, "UseXVidMode", buffer, sizeof(buffer) ))
326 usexvidmode = IS_OPTION_TRUE( buffer[0] );
328 if (!get_config_key( hkey, appkey, "UseXRandR", buffer, sizeof(buffer) ))
329 usexrandr = IS_OPTION_TRUE( buffer[0] );
331 if (!get_config_key( hkey, appkey, "UseTakeFocus", buffer, sizeof(buffer) ))
332 use_take_focus = IS_OPTION_TRUE( buffer[0] );
334 if (!get_config_key( hkey, appkey, "UsePrimarySelection", buffer, sizeof(buffer) ))
335 use_primary_selection = IS_OPTION_TRUE( buffer[0] );
337 screen_depth = 0;
338 if (!get_config_key( hkey, appkey, "ScreenDepth", buffer, sizeof(buffer) ))
339 screen_depth = atoi(buffer);
341 if (!get_config_key( hkey, appkey, "ClientSideWithCore", buffer, sizeof(buffer) ))
342 client_side_with_core = IS_OPTION_TRUE( buffer[0] );
344 if (!get_config_key( hkey, appkey, "ClientSideWithRender", buffer, sizeof(buffer) ))
345 client_side_with_render = IS_OPTION_TRUE( buffer[0] );
347 if (!get_config_key( hkey, appkey, "ClientSideAntiAliasWithCore", buffer, sizeof(buffer) ))
348 client_side_antialias_with_core = IS_OPTION_TRUE( buffer[0] );
350 if (!get_config_key( hkey, appkey, "ClientSideAntiAliasWithRender", buffer, sizeof(buffer) ))
351 client_side_antialias_with_render = IS_OPTION_TRUE( buffer[0] );
353 if (!get_config_key( hkey, appkey, "UseXIM", buffer, sizeof(buffer) ))
354 use_xim = IS_OPTION_TRUE( buffer[0] );
356 if (!get_config_key( hkey, appkey, "PrivateColorMap", buffer, sizeof(buffer) ))
357 private_color_map = IS_OPTION_TRUE( buffer[0] );
359 if (!get_config_key( hkey, appkey, "PrimaryMonitor", buffer, sizeof(buffer) ))
360 primary_monitor = atoi( buffer );
362 if (!get_config_key( hkey, appkey, "CopyDefaultColors", buffer, sizeof(buffer) ))
363 copy_default_colors = atoi(buffer);
365 if (!get_config_key( hkey, appkey, "AllocSystemColors", buffer, sizeof(buffer) ))
366 alloc_system_colors = atoi(buffer);
368 get_config_key( hkey, appkey, "InputStyle", input_style, sizeof(input_style) );
370 if (appkey) RegCloseKey( appkey );
371 if (hkey) RegCloseKey( hkey );
375 /***********************************************************************
376 * X11DRV process initialisation routine
378 static BOOL process_attach(void)
380 Display *display;
381 XVisualInfo *desktop_vi = NULL;
382 const char *env;
384 setup_options();
386 if ((thread_data_tls_index = TlsAlloc()) == TLS_OUT_OF_INDEXES) return FALSE;
388 /* Open display */
390 if (!(env = getenv("XMODIFIERS")) || !*env) /* try to avoid the Xlib XIM locking bug */
391 if (!XInitThreads()) ERR( "XInitThreads failed, trouble ahead\n" );
393 if (!(display = XOpenDisplay( NULL ))) return FALSE;
395 fcntl( ConnectionNumber(display), F_SETFD, 1 ); /* set close on exec flag */
396 screen = DefaultScreenOfDisplay( display );
397 visual = DefaultVisual( display, DefaultScreen(display) );
398 root_window = DefaultRootWindow( display );
399 gdi_display = display;
400 old_error_handler = XSetErrorHandler( error_handler );
402 /* Initialize screen depth */
404 if (screen_depth) /* depth specified */
406 int depth_count, i;
407 int *depth_list = XListDepths(display, DefaultScreen(display), &depth_count);
408 for (i = 0; i < depth_count; i++)
409 if (depth_list[i] == screen_depth) break;
410 XFree( depth_list );
411 if (i >= depth_count)
413 WARN( "invalid depth %d, using default\n", screen_depth );
414 screen_depth = 0;
417 if (!screen_depth) screen_depth = DefaultDepthOfScreen( screen );
419 /* If OpenGL is available, change the default visual, etc as necessary */
420 if ((desktop_vi = X11DRV_setup_opengl_visual( display )))
422 visual = desktop_vi->visual;
423 screen = ScreenOfDisplay(display, desktop_vi->screen);
424 screen_depth = desktop_vi->depth;
425 XFree(desktop_vi);
428 XInternAtoms( display, (char **)atom_names, NB_XATOMS - FIRST_XATOM, False, X11DRV_Atoms );
430 if (TRACE_ON(synchronous)) XSynchronize( display, True );
432 screen_width = WidthOfScreen( screen );
433 screen_height = HeightOfScreen( screen );
435 xinerama_init();
436 X11DRV_Settings_Init();
438 #ifdef HAVE_LIBXXF86VM
439 /* initialize XVidMode */
440 X11DRV_XF86VM_Init();
441 #endif
442 #ifdef HAVE_LIBXRANDR
443 /* initialize XRandR */
444 X11DRV_XRandR_Init();
445 #endif
447 X11DRV_ClipCursor( NULL );
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 X11DRV_ResetSelectionOwner();
465 wine_tsx11_lock();
466 if (data->xim) XCloseIM( data->xim );
467 XCloseDisplay( data->display );
468 wine_tsx11_unlock();
469 HeapFree( GetProcessHeap(), 0, data );
474 /***********************************************************************
475 * X11DRV process termination routine
477 static void process_detach(void)
479 #ifdef HAVE_LIBXXF86VM
480 /* cleanup XVidMode */
481 X11DRV_XF86VM_Cleanup();
482 #endif
483 if(using_client_side_fonts)
484 X11DRV_XRender_Finalize();
486 /* cleanup GDI */
487 X11DRV_GDI_Finalize();
489 DeleteCriticalSection( &X11DRV_CritSection );
490 TlsFree( thread_data_tls_index );
494 /* store the display fd into the message queue */
495 static void set_queue_display_fd( Display *display )
497 HANDLE handle;
498 int ret;
500 if (wine_server_fd_to_handle( ConnectionNumber(display), GENERIC_READ | SYNCHRONIZE, 0, &handle ))
502 MESSAGE( "x11drv: Can't allocate handle for display fd\n" );
503 ExitProcess(1);
505 SERVER_START_REQ( set_queue_fd )
507 req->handle = handle;
508 ret = wine_server_call( req );
510 SERVER_END_REQ;
511 if (ret)
513 MESSAGE( "x11drv: Can't store handle for display fd\n" );
514 ExitProcess(1);
516 CloseHandle( handle );
520 /***********************************************************************
521 * X11DRV thread initialisation routine
523 struct x11drv_thread_data *x11drv_init_thread_data(void)
525 struct x11drv_thread_data *data;
527 if (!(data = HeapAlloc( GetProcessHeap(), 0, sizeof(*data) )))
529 ERR( "could not create data\n" );
530 ExitProcess(1);
532 wine_tsx11_lock();
533 if (!(data->display = XOpenDisplay(NULL)))
535 wine_tsx11_unlock();
536 MESSAGE( "x11drv: Can't open display: %s\n", XDisplayName(NULL) );
537 MESSAGE( "Please ensure that your X server is running and that $DISPLAY is set correctly.\n" );
538 ExitProcess(1);
541 fcntl( ConnectionNumber(data->display), F_SETFD, 1 ); /* set close on exec flag */
543 #ifdef HAVE_XKB
544 if (use_xkb)
546 use_xkb = XkbUseExtension( data->display, NULL, NULL );
547 if (use_xkb)
549 /* Hack: dummy call to XkbKeysymToModifiers to force initialisation of Xkb internals */
550 /* This works around an Xlib bug where it tries to get the display lock */
551 /* twice during XFilterEvents if Xkb hasn't been initialised yet. */
552 XkbKeysymToModifiers( data->display, 'A' );
553 XkbSetDetectableAutoRepeat( data->display, True, NULL );
556 #endif
558 if (TRACE_ON(synchronous)) XSynchronize( data->display, True );
559 wine_tsx11_unlock();
561 if (!use_xim)
562 data->xim = NULL;
563 else if (!(data->xim = X11DRV_SetupXIM( data->display, input_style )))
564 WARN("Input Method is not available\n");
566 set_queue_display_fd( data->display );
567 data->process_event_count = 0;
568 data->cursor = None;
569 data->cursor_window = None;
570 data->grab_window = None;
571 data->last_focus = 0;
572 data->selection_wnd = 0;
573 TlsSetValue( thread_data_tls_index, data );
574 return data;
578 /***********************************************************************
579 * X11DRV initialisation routine
581 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
583 BOOL ret = TRUE;
585 switch(reason)
587 case DLL_PROCESS_ATTACH:
588 ret = process_attach();
589 break;
590 case DLL_THREAD_DETACH:
591 thread_detach();
592 break;
593 case DLL_PROCESS_DETACH:
594 process_detach();
595 break;
597 return ret;
600 /***********************************************************************
601 * GetScreenSaveActive (X11DRV.@)
603 * Returns the active status of the screen saver
605 BOOL X11DRV_GetScreenSaveActive(void)
607 int timeout, temp;
608 wine_tsx11_lock();
609 XGetScreenSaver(gdi_display, &timeout, &temp, &temp, &temp);
610 wine_tsx11_unlock();
611 return timeout != 0;
614 /***********************************************************************
615 * SetScreenSaveActive (X11DRV.@)
617 * Activate/Deactivate the screen saver
619 void X11DRV_SetScreenSaveActive(BOOL bActivate)
621 int timeout, interval, prefer_blanking, allow_exposures;
622 static int last_timeout = 15 * 60;
624 wine_tsx11_lock();
625 XGetScreenSaver(gdi_display, &timeout, &interval, &prefer_blanking,
626 &allow_exposures);
627 if (timeout) last_timeout = timeout;
629 timeout = bActivate ? last_timeout : 0;
630 XSetScreenSaver(gdi_display, timeout, interval, prefer_blanking,
631 allow_exposures);
632 wine_tsx11_unlock();