Added Finnish resources.
[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
55 static CRITICAL_SECTION X11DRV_CritSection;
56 static CRITICAL_SECTION_DEBUG critsect_debug =
57 {
58     0, 0, &X11DRV_CritSection,
59     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
60       0, 0, { (DWORD_PTR)(__FILE__ ": X11DRV_CritSection") }
61 };
62 static CRITICAL_SECTION X11DRV_CritSection = { &critsect_debug, -1, 0, 0, 0, 0 };
63
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;
88
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;
93
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];
102
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')
107
108 Atom X11DRV_Atoms[NB_XATOMS - FIRST_XATOM];
109
110 static const char * const atom_names[NB_XATOMS - FIRST_XATOM] =
111 {
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"
157 };
158
159 /***********************************************************************
160  *              ignore_error
161  *
162  * Check if the X error is one we can ignore.
163  */
164 static inline BOOL ignore_error( Display *display, XErrorEvent *event )
165 {
166     if (event->request_code == X_SetInputFocus && event->error_code == BadMatch) return TRUE;
167     return FALSE;
168 }
169
170
171 /***********************************************************************
172  *              X11DRV_expect_error
173  *
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.
178  */
179 void X11DRV_expect_error( Display *display, x11drv_error_callback callback, void *arg )
180 {
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);
187 }
188
189
190 /***********************************************************************
191  *              X11DRV_check_error
192  *
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.
196  */
197 int X11DRV_check_error(void)
198 {
199     int ret;
200     err_callback = NULL;
201     ret = err_callback_result;
202     wine_tsx11_unlock();
203     return ret;
204 }
205
206
207 /***********************************************************************
208  *              error_handler
209  */
210 static int error_handler( Display *display, XErrorEvent *error_evt )
211 {
212     if (err_callback && display == err_callback_display &&
213         (long)(error_evt->serial - err_serial) >= 0)
214     {
215         if ((err_callback_result = err_callback( display, error_evt, err_callback_arg )))
216         {
217             TRACE( "got expected error %d req %d\n",
218                    error_evt->error_code, error_evt->request_code );
219             return 0;
220         }
221     }
222     if (ignore_error( display, error_evt ))
223     {
224         TRACE( "got ignored error %d req %d\n",
225                error_evt->error_code, error_evt->request_code );
226         return 0;
227     }
228     if (synchronous)
229     {
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 */
233     }
234     old_error_handler( display, error_evt );
235     return 0;
236 }
237
238 /***********************************************************************
239  *              wine_tsx11_lock   (X11DRV.@)
240  */
241 void wine_tsx11_lock(void)
242 {
243     EnterCriticalSection( &X11DRV_CritSection );
244 }
245
246 /***********************************************************************
247  *              wine_tsx11_unlock   (X11DRV.@)
248  */
249 void wine_tsx11_unlock(void)
250 {
251     LeaveCriticalSection( &X11DRV_CritSection );
252 }
253
254
255 /***********************************************************************
256  *              get_config_key
257  *
258  * Get a config key from either the app-specific or the default config
259  */
260 inline static DWORD get_config_key( HKEY defkey, HKEY appkey, const char *name,
261                                     char *buffer, DWORD size )
262 {
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;
266 }
267
268
269 /***********************************************************************
270  *              setup_options
271  *
272  * Setup the x11drv options.
273  */
274 static void setup_options(void)
275 {
276     char buffer[MAX_PATH+16];
277     HKEY hkey, appkey = 0;
278     DWORD len;
279
280     /* @@ Wine registry key: HKCU\Software\Wine\X11 Driver */
281     if (RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\X11 Driver", &hkey )) hkey = 0;
282
283     /* open the app-specific key */
284
285     len = (GetModuleFileNameA( 0, buffer, MAX_PATH ));
286     if (len && len < MAX_PATH)
287     {
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 ))
295         {
296             if (RegOpenKeyA( tmpkey, appname, &appkey )) appkey = 0;
297             RegCloseKey( tmpkey );
298         }
299     }
300
301     if (!get_config_key( hkey, appkey, "Desktop", buffer, sizeof(buffer) ))
302     {
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);
307     }
308
309     if (!get_config_key( hkey, appkey, "Managed", buffer, sizeof(buffer) ))
310         managed_mode = IS_OPTION_TRUE( buffer[0] );
311
312     if (!get_config_key( hkey, appkey, "DXGrab", buffer, sizeof(buffer) ))
313         dxgrab = IS_OPTION_TRUE( buffer[0] );
314
315     if (!get_config_key( hkey, appkey, "UseDGA", buffer, sizeof(buffer) ))
316         usedga = IS_OPTION_TRUE( buffer[0] );
317
318     if (!get_config_key( hkey, appkey, "UseXVidMode", buffer, sizeof(buffer) ))
319         usexvidmode = IS_OPTION_TRUE( buffer[0] );
320
321     if (!get_config_key( hkey, appkey, "UseXRandR", buffer, sizeof(buffer) ))
322         usexrandr = IS_OPTION_TRUE( buffer[0] );
323
324     if (!get_config_key( hkey, appkey, "UseTakeFocus", buffer, sizeof(buffer) ))
325         use_take_focus = IS_OPTION_TRUE( buffer[0] );
326
327     if (!get_config_key( hkey, appkey, "UsePrimarySelection", buffer, sizeof(buffer) ))
328         use_primary_selection = IS_OPTION_TRUE( buffer[0] );
329
330     screen_depth = 0;
331     if (!get_config_key( hkey, appkey, "ScreenDepth", buffer, sizeof(buffer) ))
332         screen_depth = atoi(buffer);
333
334     if (!get_config_key( hkey, appkey, "Synchronous", buffer, sizeof(buffer) ))
335         synchronous = IS_OPTION_TRUE( buffer[0] );
336
337     if (!get_config_key( hkey, appkey, "ClientSideWithCore", buffer, sizeof(buffer) ))
338         client_side_with_core = IS_OPTION_TRUE( buffer[0] );
339
340     if (!get_config_key( hkey, appkey, "ClientSideWithRender", buffer, sizeof(buffer) ))
341         client_side_with_render = IS_OPTION_TRUE( buffer[0] );
342
343     if (!get_config_key( hkey, appkey, "ClientSideAntiAliasWithCore", buffer, sizeof(buffer) ))
344         client_side_antialias_with_core = IS_OPTION_TRUE( buffer[0] );
345
346     if (!get_config_key( hkey, appkey, "ClientSideAntiAliasWithRender", buffer, sizeof(buffer) ))
347         client_side_antialias_with_render = IS_OPTION_TRUE( buffer[0] );
348
349     if (!get_config_key( hkey, appkey, "DesktopDoubleBuffered", buffer, sizeof(buffer) ))
350         desktop_dbl_buf = 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, "CopyDefaultColors", buffer, sizeof(buffer) ))
359         copy_default_colors = atoi(buffer);
360
361     if (!get_config_key( hkey, appkey, "AllocSystemColors", buffer, sizeof(buffer) ))
362         alloc_system_colors = atoi(buffer);
363
364     get_config_key( hkey, appkey, "InputStyle", input_style, sizeof(input_style) );
365
366     if (appkey) RegCloseKey( appkey );
367     if (hkey) RegCloseKey( hkey );
368 }
369
370
371 /***********************************************************************
372  *           X11DRV process initialisation routine
373  */
374 static BOOL process_attach(void)
375 {
376     Display *display;
377
378     setup_options();
379
380     if ((thread_data_tls_index = TlsAlloc()) == TLS_OUT_OF_INDEXES) return FALSE;
381
382     /* Open display */
383
384     if (!(display = XOpenDisplay( NULL ))) return FALSE;
385
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 );
392
393     /* Initialize screen depth */
394
395     if (screen_depth)  /* depth specified */
396     {
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)
403         {
404             WARN( "invalid depth %d, using default\n", screen_depth );
405             screen_depth = 0;
406         }
407     }
408     if (!screen_depth) screen_depth = DefaultDepthOfScreen( screen );
409
410     /* If OpenGL is available, change the default visual, etc as necessary */
411     if (desktop_dbl_buf && (desktop_vi = X11DRV_setup_opengl_visual( display )))
412     {
413         visual       = desktop_vi->visual;
414         screen       = ScreenOfDisplay(display, desktop_vi->screen);
415         screen_depth = desktop_vi->depth;
416     }
417
418     XInternAtoms( display, (char **)atom_names, NB_XATOMS - FIRST_XATOM, False, X11DRV_Atoms );
419
420     if (synchronous) XSynchronize( display, True );
421
422     screen_width  = WidthOfScreen( screen );
423     screen_height = HeightOfScreen( screen );
424
425     X11DRV_Settings_Init();
426
427     if (desktop_geometry)
428     {
429         root_window = X11DRV_create_desktop( desktop_vi, desktop_geometry );
430         using_wine_desktop = 1;
431     }
432
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
445
446     X11DRV_InitKeyboard();
447     X11DRV_InitClipboard();
448
449     return TRUE;
450 }
451
452
453 /***********************************************************************
454  *           X11DRV thread termination routine
455  */
456 static void thread_detach(void)
457 {
458     struct x11drv_thread_data *data = TlsGetValue( thread_data_tls_index );
459
460     if (data)
461     {
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 );
468     }
469 }
470
471
472 /***********************************************************************
473  *           X11DRV process termination routine
474  */
475 static void process_detach(void)
476 {
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();
487
488     /* cleanup GDI */
489     X11DRV_GDI_Finalize();
490
491     DeleteCriticalSection( &X11DRV_CritSection );
492     TlsFree( thread_data_tls_index );
493 }
494
495
496 /***********************************************************************
497  *           X11DRV thread initialisation routine
498  */
499 struct x11drv_thread_data *x11drv_init_thread_data(void)
500 {
501     struct x11drv_thread_data *data;
502
503     if (!(data = HeapAlloc( GetProcessHeap(), 0, sizeof(*data) )))
504     {
505         ERR( "could not create data\n" );
506         ExitProcess(1);
507     }
508     wine_tsx11_lock();
509     if (!(data->display = XOpenDisplay(NULL)))
510     {
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);
515     }
516
517     fcntl( ConnectionNumber(data->display), F_SETFD, 1 ); /* set close on exec flag */
518
519 #ifdef HAVE_XKB
520     if (use_xkb)
521     {
522         use_xkb = XkbUseExtension( data->display, NULL, NULL );
523         if (use_xkb) XkbSetDetectableAutoRepeat( data->display, True, NULL );
524     }
525 #endif
526
527     if (synchronous) XSynchronize( data->display, True );
528     wine_tsx11_unlock();
529
530     if (use_xim && !(data->xim = X11DRV_SetupXIM( data->display, input_style )))
531         WARN("Input Method is not available\n");
532
533     if (wine_server_fd_to_handle( ConnectionNumber(data->display), GENERIC_READ | SYNCHRONIZE,
534                                   FALSE, &data->display_fd ))
535     {
536         MESSAGE( "x11drv: Can't allocate handle for display fd\n" );
537         ExitProcess(1);
538     }
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;
548 }
549
550
551 /***********************************************************************
552  *           X11DRV initialisation routine
553  */
554 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
555 {
556     BOOL ret = TRUE;
557
558     switch(reason)
559     {
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;
569     }
570     return ret;
571 }
572
573 /***********************************************************************
574  *              GetScreenSaveActive (X11DRV.@)
575  *
576  * Returns the active status of the screen saver
577  */
578 BOOL X11DRV_GetScreenSaveActive(void)
579 {
580     int timeout, temp;
581     wine_tsx11_lock();
582     XGetScreenSaver(gdi_display, &timeout, &temp, &temp, &temp);
583     wine_tsx11_unlock();
584     return timeout != 0;
585 }
586
587 /***********************************************************************
588  *              SetScreenSaveActive (X11DRV.@)
589  *
590  * Activate/Deactivate the screen saver
591  */
592 void X11DRV_SetScreenSaveActive(BOOL bActivate)
593 {
594     int timeout, interval, prefer_blanking, allow_exposures;
595     static int last_timeout = 15 * 60;
596
597     wine_tsx11_lock();
598     XGetScreenSaver(gdi_display, &timeout, &interval, &prefer_blanking,
599                     &allow_exposures);
600     if (timeout) last_timeout = timeout;
601
602     timeout = bActivate ? last_timeout : 0;
603     XSetScreenSaver(gdi_display, timeout, interval, prefer_blanking,
604                     allow_exposures);
605     wine_tsx11_unlock();
606 }