configure: Use --rpath when linking dlls too.
[wine] / dlls / x11drv / x11drv_main.c
1 /*
2  * X11DRV initialization code
3  *
4  * Copyright 1998 Patrik Stridvall
5  * Copyright 2000 Alexandre Julliard
6  *
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.
11  *
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.
16  *
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
20  */
21
22 #include "config.h"
23
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
41 #include "windef.h"
42 #include "winbase.h"
43 #include "wine/winbase16.h"
44 #include "winreg.h"
45
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"
52
53 WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
54 WINE_DECLARE_DEBUG_CHANNEL(synchronous);
55
56 static CRITICAL_SECTION X11DRV_CritSection;
57 static CRITICAL_SECTION_DEBUG critsect_debug =
58 {
59     0, 0, &X11DRV_CritSection,
60     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
61       0, 0, { (DWORD_PTR)(__FILE__ ": X11DRV_CritSection") }
62 };
63 static CRITICAL_SECTION X11DRV_CritSection = { &critsect_debug, -1, 0, 0, 0, 0 };
64
65 Screen *screen;
66 Visual *visual;
67 unsigned int screen_width;
68 unsigned int screen_height;
69 unsigned int screen_depth;
70 Window root_window;
71 DWORD desktop_tid = 0;
72 int dxgrab = 0;
73 int usedga = 0;
74 int usexvidmode = 0;
75 int usexrandr = 1;
76 int use_xkb = 1;
77 int use_take_focus = 1;
78 int use_primary_selection = 0;
79 int managed_mode = 1;
80 int private_color_map = 0;
81 int client_side_with_core = 1;
82 int client_side_with_render = 1;
83 int client_side_antialias_with_core = 1;
84 int client_side_antialias_with_render = 1;
85 int using_wine_desktop = 0;
86 int copy_default_colors = 128;
87 int alloc_system_colors = 256;
88 DWORD thread_data_tls_index = TLS_OUT_OF_INDEXES;
89
90 static BOOL desktop_dbl_buf = TRUE;
91 static char *desktop_geometry;
92
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];
101
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')
106
107 Atom X11DRV_Atoms[NB_XATOMS - FIRST_XATOM];
108
109 static const char * const atom_names[NB_XATOMS - FIRST_XATOM] =
110 {
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"
156 };
157
158 /***********************************************************************
159  *              ignore_error
160  *
161  * Check if the X error is one we can ignore.
162  */
163 static inline BOOL ignore_error( Display *display, XErrorEvent *event )
164 {
165     if (event->request_code == X_SetInputFocus && event->error_code == BadMatch) return TRUE;
166     return FALSE;
167 }
168
169
170 /***********************************************************************
171  *              X11DRV_expect_error
172  *
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.
177  */
178 void X11DRV_expect_error( Display *display, x11drv_error_callback callback, void *arg )
179 {
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);
186 }
187
188
189 /***********************************************************************
190  *              X11DRV_check_error
191  *
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.
195  */
196 int X11DRV_check_error(void)
197 {
198     int ret;
199     err_callback = NULL;
200     ret = err_callback_result;
201     wine_tsx11_unlock();
202     return ret;
203 }
204
205
206 /***********************************************************************
207  *              error_handler
208  */
209 static int error_handler( Display *display, XErrorEvent *error_evt )
210 {
211     if (err_callback && display == err_callback_display &&
212         (long)(error_evt->serial - err_serial) >= 0)
213     {
214         if ((err_callback_result = err_callback( display, error_evt, err_callback_arg )))
215         {
216             TRACE( "got expected error %d req %d\n",
217                    error_evt->error_code, error_evt->request_code );
218             return 0;
219         }
220     }
221     if (ignore_error( display, error_evt ))
222     {
223         TRACE( "got ignored error %d req %d\n",
224                error_evt->error_code, error_evt->request_code );
225         return 0;
226     }
227     if (TRACE_ON(synchronous))
228     {
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 */
232     }
233     old_error_handler( display, error_evt );
234     return 0;
235 }
236
237 /***********************************************************************
238  *              wine_tsx11_lock   (X11DRV.@)
239  */
240 void wine_tsx11_lock(void)
241 {
242     EnterCriticalSection( &X11DRV_CritSection );
243 }
244
245 /***********************************************************************
246  *              wine_tsx11_unlock   (X11DRV.@)
247  */
248 void wine_tsx11_unlock(void)
249 {
250     LeaveCriticalSection( &X11DRV_CritSection );
251 }
252
253
254 /***********************************************************************
255  *              get_config_key
256  *
257  * Get a config key from either the app-specific or the default config
258  */
259 inline static DWORD get_config_key( HKEY defkey, HKEY appkey, const char *name,
260                                     char *buffer, DWORD size )
261 {
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;
265 }
266
267
268 /***********************************************************************
269  *              setup_options
270  *
271  * Setup the x11drv options.
272  */
273 static void setup_options(void)
274 {
275     char buffer[MAX_PATH+16];
276     HKEY hkey, appkey = 0;
277     DWORD len;
278
279     /* @@ Wine registry key: HKCU\Software\Wine\X11 Driver */
280     if (RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\X11 Driver", &hkey )) hkey = 0;
281
282     /* open the app-specific key */
283
284     len = (GetModuleFileNameA( 0, buffer, MAX_PATH ));
285     if (len && len < MAX_PATH)
286     {
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 ))
294         {
295             if (RegOpenKeyA( tmpkey, appname, &appkey )) appkey = 0;
296             RegCloseKey( tmpkey );
297         }
298     }
299
300     if (!get_config_key( hkey, appkey, "Desktop", buffer, sizeof(buffer) ))
301     {
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);
306     }
307
308     if (!get_config_key( hkey, appkey, "Managed", buffer, sizeof(buffer) ))
309         managed_mode = IS_OPTION_TRUE( buffer[0] );
310
311     if (!get_config_key( hkey, appkey, "DXGrab", buffer, sizeof(buffer) ))
312         dxgrab = IS_OPTION_TRUE( buffer[0] );
313
314     if (!get_config_key( hkey, appkey, "UseDGA", buffer, sizeof(buffer) ))
315         usedga = IS_OPTION_TRUE( buffer[0] );
316
317     if (!get_config_key( hkey, appkey, "UseXVidMode", buffer, sizeof(buffer) ))
318         usexvidmode = IS_OPTION_TRUE( buffer[0] );
319
320     if (!get_config_key( hkey, appkey, "UseXRandR", buffer, sizeof(buffer) ))
321         usexrandr = IS_OPTION_TRUE( buffer[0] );
322
323     if (!get_config_key( hkey, appkey, "UseTakeFocus", buffer, sizeof(buffer) ))
324         use_take_focus = IS_OPTION_TRUE( buffer[0] );
325
326     if (!get_config_key( hkey, appkey, "UsePrimarySelection", buffer, sizeof(buffer) ))
327         use_primary_selection = IS_OPTION_TRUE( buffer[0] );
328
329     screen_depth = 0;
330     if (!get_config_key( hkey, appkey, "ScreenDepth", buffer, sizeof(buffer) ))
331         screen_depth = atoi(buffer);
332
333     if (!get_config_key( hkey, appkey, "ClientSideWithCore", buffer, sizeof(buffer) ))
334         client_side_with_core = IS_OPTION_TRUE( buffer[0] );
335
336     if (!get_config_key( hkey, appkey, "ClientSideWithRender", buffer, sizeof(buffer) ))
337         client_side_with_render = IS_OPTION_TRUE( buffer[0] );
338
339     if (!get_config_key( hkey, appkey, "ClientSideAntiAliasWithCore", buffer, sizeof(buffer) ))
340         client_side_antialias_with_core = IS_OPTION_TRUE( buffer[0] );
341
342     if (!get_config_key( hkey, appkey, "ClientSideAntiAliasWithRender", buffer, sizeof(buffer) ))
343         client_side_antialias_with_render = IS_OPTION_TRUE( buffer[0] );
344
345     if (!get_config_key( hkey, appkey, "DesktopDoubleBuffered", buffer, sizeof(buffer) ))
346         desktop_dbl_buf = IS_OPTION_TRUE( buffer[0] );
347
348     if (!get_config_key( hkey, appkey, "UseXIM", buffer, sizeof(buffer) ))
349         use_xim = IS_OPTION_TRUE( buffer[0] );
350
351     if (!get_config_key( hkey, appkey, "PrivateColorMap", buffer, sizeof(buffer) ))
352         private_color_map = IS_OPTION_TRUE( buffer[0] );
353
354     if (!get_config_key( hkey, appkey, "CopyDefaultColors", buffer, sizeof(buffer) ))
355         copy_default_colors = atoi(buffer);
356
357     if (!get_config_key( hkey, appkey, "AllocSystemColors", buffer, sizeof(buffer) ))
358         alloc_system_colors = atoi(buffer);
359
360     get_config_key( hkey, appkey, "InputStyle", input_style, sizeof(input_style) );
361
362     if (appkey) RegCloseKey( appkey );
363     if (hkey) RegCloseKey( hkey );
364 }
365
366
367 /***********************************************************************
368  *           X11DRV process initialisation routine
369  */
370 static BOOL process_attach(void)
371 {
372     Display *display;
373     XVisualInfo *desktop_vi = NULL;
374
375     setup_options();
376
377     if ((thread_data_tls_index = TlsAlloc()) == TLS_OUT_OF_INDEXES) return FALSE;
378
379     /* Open display */
380
381     if (!(display = XOpenDisplay( NULL ))) return FALSE;
382
383     fcntl( ConnectionNumber(display), F_SETFD, 1 ); /* set close on exec flag */
384     screen = DefaultScreenOfDisplay( display );
385     visual = DefaultVisual( display, DefaultScreen(display) );
386     root_window = DefaultRootWindow( display );
387     gdi_display = display;
388     old_error_handler = XSetErrorHandler( error_handler );
389
390     /* Initialize screen depth */
391
392     if (screen_depth)  /* depth specified */
393     {
394         int depth_count, i;
395         int *depth_list = XListDepths(display, DefaultScreen(display), &depth_count);
396         for (i = 0; i < depth_count; i++)
397             if (depth_list[i] == screen_depth) break;
398         XFree( depth_list );
399         if (i >= depth_count)
400         {
401             WARN( "invalid depth %d, using default\n", screen_depth );
402             screen_depth = 0;
403         }
404     }
405     if (!screen_depth) screen_depth = DefaultDepthOfScreen( screen );
406
407     /* If OpenGL is available, change the default visual, etc as necessary */
408     if (desktop_dbl_buf && (desktop_vi = X11DRV_setup_opengl_visual( display )))
409     {
410         visual       = desktop_vi->visual;
411         screen       = ScreenOfDisplay(display, desktop_vi->screen);
412         screen_depth = desktop_vi->depth;
413     }
414
415     XInternAtoms( display, (char **)atom_names, NB_XATOMS - FIRST_XATOM, False, X11DRV_Atoms );
416
417     if (TRACE_ON(synchronous)) XSynchronize( display, True );
418
419     screen_width  = WidthOfScreen( screen );
420     screen_height = HeightOfScreen( screen );
421
422     X11DRV_Settings_Init();
423
424     if (desktop_geometry)
425     {
426         root_window = X11DRV_create_desktop( desktop_vi, desktop_geometry );
427         using_wine_desktop = 1;
428     }
429     if(desktop_vi)
430         XFree(desktop_vi);
431
432 #ifdef HAVE_LIBXXF86VM
433     /* initialize XVidMode */
434     X11DRV_XF86VM_Init();
435 #endif
436 #ifdef HAVE_LIBXRANDR
437     /* initialize XRandR */
438     X11DRV_XRandR_Init();
439 #endif
440 #ifdef HAVE_LIBXXF86DGA2
441     /* initialize DGA2 */
442     X11DRV_XF86DGA2_Init();
443 #endif
444
445     X11DRV_InitKeyboard();
446     X11DRV_InitClipboard();
447
448     return TRUE;
449 }
450
451
452 /***********************************************************************
453  *           X11DRV thread termination routine
454  */
455 static void thread_detach(void)
456 {
457     struct x11drv_thread_data *data = TlsGetValue( thread_data_tls_index );
458
459     if (data)
460     {
461         CloseHandle( data->display_fd );
462         wine_tsx11_lock();
463         XCloseDisplay( data->display );
464         /* if (data->xim) XCloseIM( data->xim ); */ /* crashes Xlib */
465         wine_tsx11_unlock();
466         HeapFree( GetProcessHeap(), 0, data );
467     }
468 }
469
470
471 /***********************************************************************
472  *           X11DRV process termination routine
473  */
474 static void process_detach(void)
475 {
476 #ifdef HAVE_LIBXXF86DGA2
477     /* cleanup DGA2 */
478     X11DRV_XF86DGA2_Cleanup();
479 #endif
480 #ifdef HAVE_LIBXXF86VM
481     /* cleanup XVidMode */
482     X11DRV_XF86VM_Cleanup();
483 #endif
484     if(using_client_side_fonts)
485         X11DRV_XRender_Finalize();
486
487     /* cleanup GDI */
488     X11DRV_GDI_Finalize();
489
490     DeleteCriticalSection( &X11DRV_CritSection );
491     TlsFree( thread_data_tls_index );
492 }
493
494
495 /***********************************************************************
496  *           X11DRV thread initialisation routine
497  */
498 struct x11drv_thread_data *x11drv_init_thread_data(void)
499 {
500     struct x11drv_thread_data *data;
501
502     if (!(data = HeapAlloc( GetProcessHeap(), 0, sizeof(*data) )))
503     {
504         ERR( "could not create data\n" );
505         ExitProcess(1);
506     }
507     wine_tsx11_lock();
508     if (!(data->display = XOpenDisplay(NULL)))
509     {
510         wine_tsx11_unlock();
511         MESSAGE( "x11drv: Can't open display: %s\n", XDisplayName(NULL) );
512         MESSAGE( "Please ensure that your X server is running and that $DISPLAY is set correctly.\n" );
513         ExitProcess(1);
514     }
515
516     fcntl( ConnectionNumber(data->display), F_SETFD, 1 ); /* set close on exec flag */
517
518 #ifdef HAVE_XKB
519     if (use_xkb)
520     {
521         use_xkb = XkbUseExtension( data->display, NULL, NULL );
522         if (use_xkb) XkbSetDetectableAutoRepeat( data->display, True, NULL );
523     }
524 #endif
525
526     if (TRACE_ON(synchronous)) XSynchronize( data->display, True );
527     wine_tsx11_unlock();
528
529     if (use_xim && !(data->xim = X11DRV_SetupXIM( data->display, input_style )))
530         WARN("Input Method is not available\n");
531
532     if (wine_server_fd_to_handle( ConnectionNumber(data->display), GENERIC_READ | SYNCHRONIZE,
533                                   0, &data->display_fd ))
534     {
535         MESSAGE( "x11drv: Can't allocate handle for display fd\n" );
536         ExitProcess(1);
537     }
538     data->process_event_count = 0;
539     data->cursor = None;
540     data->cursor_window = None;
541     data->grab_window = None;
542     data->last_focus = 0;
543     data->selection_wnd = 0;
544     TlsSetValue( thread_data_tls_index, data );
545     if (desktop_tid) AttachThreadInput( GetCurrentThreadId(), desktop_tid, TRUE );
546     return data;
547 }
548
549
550 /***********************************************************************
551  *           X11DRV initialisation routine
552  */
553 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
554 {
555     BOOL ret = TRUE;
556
557     switch(reason)
558     {
559     case DLL_PROCESS_ATTACH:
560         ret = process_attach();
561         break;
562     case DLL_THREAD_DETACH:
563         thread_detach();
564         break;
565     case DLL_PROCESS_DETACH:
566         process_detach();
567         break;
568     }
569     return ret;
570 }
571
572 /***********************************************************************
573  *              GetScreenSaveActive (X11DRV.@)
574  *
575  * Returns the active status of the screen saver
576  */
577 BOOL X11DRV_GetScreenSaveActive(void)
578 {
579     int timeout, temp;
580     wine_tsx11_lock();
581     XGetScreenSaver(gdi_display, &timeout, &temp, &temp, &temp);
582     wine_tsx11_unlock();
583     return timeout != 0;
584 }
585
586 /***********************************************************************
587  *              SetScreenSaveActive (X11DRV.@)
588  *
589  * Activate/Deactivate the screen saver
590  */
591 void X11DRV_SetScreenSaveActive(BOOL bActivate)
592 {
593     int timeout, interval, prefer_blanking, allow_exposures;
594     static int last_timeout = 15 * 60;
595
596     wine_tsx11_lock();
597     XGetScreenSaver(gdi_display, &timeout, &interval, &prefer_blanking,
598                     &allow_exposures);
599     if (timeout) last_timeout = timeout;
600
601     timeout = bActivate ? last_timeout : 0;
602     XSetScreenSaver(gdi_display, timeout, interval, prefer_blanking,
603                     allow_exposures);
604     wine_tsx11_unlock();
605 }