Change some functions arguments from () -> (void).
[wine] / dlls / winex11.drv / 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 #ifdef HAVE_X11_EXTENSIONS_XRENDER_H
41 #include <X11/extensions/Xrender.h>
42 #endif
43
44 #include "windef.h"
45 #include "winbase.h"
46 #include "wine/winbase16.h"
47 #include "winreg.h"
48
49 #include "x11drv.h"
50 #include "xvidmode.h"
51 #include "xrandr.h"
52 #include "wine/server.h"
53 #include "wine/debug.h"
54
55 WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
56 WINE_DECLARE_DEBUG_CHANNEL(synchronous);
57
58 static CRITICAL_SECTION X11DRV_CritSection;
59 static CRITICAL_SECTION_DEBUG critsect_debug =
60 {
61     0, 0, &X11DRV_CritSection,
62     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
63       0, 0, { (DWORD_PTR)(__FILE__ ": X11DRV_CritSection") }
64 };
65 static CRITICAL_SECTION X11DRV_CritSection = { &critsect_debug, -1, 0, 0, 0, 0 };
66
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;
91
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];
100
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')
105
106 Atom X11DRV_Atoms[NB_XATOMS - FIRST_XATOM];
107
108 static const char * const atom_names[NB_XATOMS - FIRST_XATOM] =
109 {
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 };
163
164 /***********************************************************************
165  *              ignore_error
166  *
167  * Check if the X error is one we can ignore.
168  */
169 static inline BOOL ignore_error( Display *display, XErrorEvent *event )
170 {
171     if (event->request_code == X_SetInputFocus && event->error_code == BadMatch) return TRUE;
172
173     /* ignore a number of errors on gdi display caused by creating/destroying windows */
174     if (display == gdi_display)
175     {
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 */
179         {
180             if (event->error_code == xrender_error_base + BadPicture) return TRUE;
181         }
182 #endif
183     }
184     return FALSE;
185 }
186
187
188 /***********************************************************************
189  *              X11DRV_expect_error
190  *
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.
195  */
196 void X11DRV_expect_error( Display *display, x11drv_error_callback callback, void *arg )
197 {
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);
204 }
205
206
207 /***********************************************************************
208  *              X11DRV_check_error
209  *
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.
213  */
214 int X11DRV_check_error(void)
215 {
216     int ret;
217     err_callback = NULL;
218     ret = err_callback_result;
219     wine_tsx11_unlock();
220     return ret;
221 }
222
223
224 /***********************************************************************
225  *              error_handler
226  */
227 static int error_handler( Display *display, XErrorEvent *error_evt )
228 {
229     if (err_callback && display == err_callback_display &&
230         (long)(error_evt->serial - err_serial) >= 0)
231     {
232         if ((err_callback_result = err_callback( display, error_evt, err_callback_arg )))
233         {
234             TRACE( "got expected error %d req %d\n",
235                    error_evt->error_code, error_evt->request_code );
236             return 0;
237         }
238     }
239     if (ignore_error( display, error_evt ))
240     {
241         TRACE( "got ignored error %d req %d\n",
242                error_evt->error_code, error_evt->request_code );
243         return 0;
244     }
245     if (TRACE_ON(synchronous))
246     {
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 */
250     }
251     old_error_handler( display, error_evt );
252     return 0;
253 }
254
255 /***********************************************************************
256  *              wine_tsx11_lock   (X11DRV.@)
257  */
258 void wine_tsx11_lock(void)
259 {
260     EnterCriticalSection( &X11DRV_CritSection );
261 }
262
263 /***********************************************************************
264  *              wine_tsx11_unlock   (X11DRV.@)
265  */
266 void wine_tsx11_unlock(void)
267 {
268     LeaveCriticalSection( &X11DRV_CritSection );
269 }
270
271
272 /***********************************************************************
273  *              get_config_key
274  *
275  * Get a config key from either the app-specific or the default config
276  */
277 inline static DWORD get_config_key( HKEY defkey, HKEY appkey, const char *name,
278                                     char *buffer, DWORD size )
279 {
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;
283 }
284
285
286 /***********************************************************************
287  *              setup_options
288  *
289  * Setup the x11drv options.
290  */
291 static void setup_options(void)
292 {
293     char buffer[MAX_PATH+16];
294     HKEY hkey, appkey = 0;
295     DWORD len;
296
297     /* @@ Wine registry key: HKCU\Software\Wine\X11 Driver */
298     if (RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\X11 Driver", &hkey )) hkey = 0;
299
300     /* open the app-specific key */
301
302     len = (GetModuleFileNameA( 0, buffer, MAX_PATH ));
303     if (len && len < MAX_PATH)
304     {
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 ))
312         {
313             if (RegOpenKeyA( tmpkey, appname, &appkey )) appkey = 0;
314             RegCloseKey( tmpkey );
315         }
316     }
317
318     if (!get_config_key( hkey, appkey, "Managed", buffer, sizeof(buffer) ))
319         managed_mode = IS_OPTION_TRUE( buffer[0] );
320
321     if (!get_config_key( hkey, appkey, "DXGrab", buffer, sizeof(buffer) ))
322         dxgrab = IS_OPTION_TRUE( buffer[0] );
323
324     if (!get_config_key( hkey, appkey, "UseXVidMode", buffer, sizeof(buffer) ))
325         usexvidmode = IS_OPTION_TRUE( buffer[0] );
326
327     if (!get_config_key( hkey, appkey, "UseXRandR", buffer, sizeof(buffer) ))
328         usexrandr = IS_OPTION_TRUE( buffer[0] );
329
330     if (!get_config_key( hkey, appkey, "UseTakeFocus", buffer, sizeof(buffer) ))
331         use_take_focus = IS_OPTION_TRUE( buffer[0] );
332
333     if (!get_config_key( hkey, appkey, "UsePrimarySelection", buffer, sizeof(buffer) ))
334         use_primary_selection = IS_OPTION_TRUE( buffer[0] );
335
336     screen_depth = 0;
337     if (!get_config_key( hkey, appkey, "ScreenDepth", buffer, sizeof(buffer) ))
338         screen_depth = atoi(buffer);
339
340     if (!get_config_key( hkey, appkey, "ClientSideWithCore", buffer, sizeof(buffer) ))
341         client_side_with_core = IS_OPTION_TRUE( buffer[0] );
342
343     if (!get_config_key( hkey, appkey, "ClientSideWithRender", buffer, sizeof(buffer) ))
344         client_side_with_render = IS_OPTION_TRUE( buffer[0] );
345
346     if (!get_config_key( hkey, appkey, "ClientSideAntiAliasWithCore", buffer, sizeof(buffer) ))
347         client_side_antialias_with_core = IS_OPTION_TRUE( buffer[0] );
348
349     if (!get_config_key( hkey, appkey, "ClientSideAntiAliasWithRender", buffer, sizeof(buffer) ))
350         client_side_antialias_with_render = IS_OPTION_TRUE( buffer[0] );
351
352     if (!get_config_key( hkey, appkey, "UseXIM", buffer, sizeof(buffer) ))
353         use_xim = IS_OPTION_TRUE( buffer[0] );
354
355     if (!get_config_key( hkey, appkey, "PrivateColorMap", buffer, sizeof(buffer) ))
356         private_color_map = IS_OPTION_TRUE( buffer[0] );
357
358     if (!get_config_key( hkey, appkey, "PrimaryMonitor", buffer, sizeof(buffer) ))
359         primary_monitor = atoi( buffer );
360
361     if (!get_config_key( hkey, appkey, "CopyDefaultColors", buffer, sizeof(buffer) ))
362         copy_default_colors = atoi(buffer);
363
364     if (!get_config_key( hkey, appkey, "AllocSystemColors", buffer, sizeof(buffer) ))
365         alloc_system_colors = atoi(buffer);
366
367     get_config_key( hkey, appkey, "InputStyle", input_style, sizeof(input_style) );
368
369     if (appkey) RegCloseKey( appkey );
370     if (hkey) RegCloseKey( hkey );
371 }
372
373
374 /***********************************************************************
375  *           X11DRV process initialisation routine
376  */
377 static BOOL process_attach(void)
378 {
379     Display *display;
380     XVisualInfo *desktop_vi = NULL;
381
382     setup_options();
383
384     if ((thread_data_tls_index = TlsAlloc()) == TLS_OUT_OF_INDEXES) return FALSE;
385
386     /* Open display */
387
388     if (!XInitThreads()) ERR( "XInitThreads failed, trouble ahead\n" );
389
390     if (!(display = XOpenDisplay( NULL ))) return FALSE;
391
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 );
398
399     /* Initialize screen depth */
400
401     if (screen_depth)  /* depth specified */
402     {
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)
409         {
410             WARN( "invalid depth %d, using default\n", screen_depth );
411             screen_depth = 0;
412         }
413     }
414     if (!screen_depth) screen_depth = DefaultDepthOfScreen( screen );
415
416     /* If OpenGL is available, change the default visual, etc as necessary */
417     if ((desktop_vi = X11DRV_setup_opengl_visual( display )))
418     {
419         visual       = desktop_vi->visual;
420         screen       = ScreenOfDisplay(display, desktop_vi->screen);
421         screen_depth = desktop_vi->depth;
422         XFree(desktop_vi);
423     }
424
425     XInternAtoms( display, (char **)atom_names, NB_XATOMS - FIRST_XATOM, False, X11DRV_Atoms );
426
427     if (TRACE_ON(synchronous)) XSynchronize( display, True );
428
429     screen_width  = WidthOfScreen( screen );
430     screen_height = HeightOfScreen( screen );
431
432     xinerama_init();
433     X11DRV_Settings_Init();
434
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
444     X11DRV_ClipCursor( NULL );
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         X11DRV_ResetSelectionOwner();
462         CloseHandle( data->display_fd );
463         wine_tsx11_lock();
464         if (data->xim) XCloseIM( data->xim );
465         XCloseDisplay( data->display );
466         wine_tsx11_unlock();
467         HeapFree( GetProcessHeap(), 0, data );
468     }
469 }
470
471
472 /***********************************************************************
473  *           X11DRV process termination routine
474  */
475 static void process_detach(void)
476 {
477 #ifdef HAVE_LIBXXF86VM
478     /* cleanup XVidMode */
479     X11DRV_XF86VM_Cleanup();
480 #endif
481     if(using_client_side_fonts)
482         X11DRV_XRender_Finalize();
483
484     /* cleanup GDI */
485     X11DRV_GDI_Finalize();
486
487     DeleteCriticalSection( &X11DRV_CritSection );
488     TlsFree( thread_data_tls_index );
489 }
490
491
492 /***********************************************************************
493  *           X11DRV thread initialisation routine
494  */
495 struct x11drv_thread_data *x11drv_init_thread_data(void)
496 {
497     struct x11drv_thread_data *data;
498
499     if (!(data = HeapAlloc( GetProcessHeap(), 0, sizeof(*data) )))
500     {
501         ERR( "could not create data\n" );
502         ExitProcess(1);
503     }
504     wine_tsx11_lock();
505     if (!(data->display = XOpenDisplay(NULL)))
506     {
507         wine_tsx11_unlock();
508         MESSAGE( "x11drv: Can't open display: %s\n", XDisplayName(NULL) );
509         MESSAGE( "Please ensure that your X server is running and that $DISPLAY is set correctly.\n" );
510         ExitProcess(1);
511     }
512
513     fcntl( ConnectionNumber(data->display), F_SETFD, 1 ); /* set close on exec flag */
514
515 #ifdef HAVE_XKB
516     if (use_xkb)
517     {
518         use_xkb = XkbUseExtension( data->display, NULL, NULL );
519         if (use_xkb)
520         {
521             /* Hack: dummy call to XkbKeysymToModifiers to force initialisation of Xkb internals */
522             /* This works around an Xlib bug where it tries to get the display lock */
523             /* twice during XFilterEvents if Xkb hasn't been initialised yet. */
524             XkbKeysymToModifiers( data->display, 'A' );
525             XkbSetDetectableAutoRepeat( data->display, True, NULL );
526         }
527     }
528 #endif
529
530     if (TRACE_ON(synchronous)) XSynchronize( data->display, True );
531     wine_tsx11_unlock();
532
533     if (!use_xim)
534         data->xim = NULL;
535     else if (!(data->xim = X11DRV_SetupXIM( data->display, input_style )))
536         WARN("Input Method is not available\n");
537
538     if (wine_server_fd_to_handle( ConnectionNumber(data->display), GENERIC_READ | SYNCHRONIZE,
539                                   0, &data->display_fd ))
540     {
541         MESSAGE( "x11drv: Can't allocate handle for display fd\n" );
542         ExitProcess(1);
543     }
544     data->process_event_count = 0;
545     data->cursor = None;
546     data->cursor_window = None;
547     data->grab_window = None;
548     data->last_focus = 0;
549     data->selection_wnd = 0;
550     TlsSetValue( thread_data_tls_index, data );
551     return data;
552 }
553
554
555 /***********************************************************************
556  *           X11DRV initialisation routine
557  */
558 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
559 {
560     BOOL ret = TRUE;
561
562     switch(reason)
563     {
564     case DLL_PROCESS_ATTACH:
565         ret = process_attach();
566         break;
567     case DLL_THREAD_DETACH:
568         thread_detach();
569         break;
570     case DLL_PROCESS_DETACH:
571         process_detach();
572         break;
573     }
574     return ret;
575 }
576
577 /***********************************************************************
578  *              GetScreenSaveActive (X11DRV.@)
579  *
580  * Returns the active status of the screen saver
581  */
582 BOOL X11DRV_GetScreenSaveActive(void)
583 {
584     int timeout, temp;
585     wine_tsx11_lock();
586     XGetScreenSaver(gdi_display, &timeout, &temp, &temp, &temp);
587     wine_tsx11_unlock();
588     return timeout != 0;
589 }
590
591 /***********************************************************************
592  *              SetScreenSaveActive (X11DRV.@)
593  *
594  * Activate/Deactivate the screen saver
595  */
596 void X11DRV_SetScreenSaveActive(BOOL bActivate)
597 {
598     int timeout, interval, prefer_blanking, allow_exposures;
599     static int last_timeout = 15 * 60;
600
601     wine_tsx11_lock();
602     XGetScreenSaver(gdi_display, &timeout, &interval, &prefer_blanking,
603                     &allow_exposures);
604     if (timeout) last_timeout = timeout;
605
606     timeout = bActivate ? last_timeout : 0;
607     XSetScreenSaver(gdi_display, timeout, interval, prefer_blanking,
608                     allow_exposures);
609     wine_tsx11_unlock();
610 }