crypt32: Implement file stores.
[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 "dga2.h"
53 #include "wine/server.h"
54 #include "wine/debug.h"
55
56 WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
57 WINE_DECLARE_DEBUG_CHANNEL(synchronous);
58
59 static CRITICAL_SECTION X11DRV_CritSection;
60 static CRITICAL_SECTION_DEBUG critsect_debug =
61 {
62     0, 0, &X11DRV_CritSection,
63     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
64       0, 0, { (DWORD_PTR)(__FILE__ ": X11DRV_CritSection") }
65 };
66 static CRITICAL_SECTION X11DRV_CritSection = { &critsect_debug, -1, 0, 0, 0, 0 };
67
68 Screen *screen;
69 Visual *visual;
70 unsigned int screen_width;
71 unsigned int screen_height;
72 unsigned int screen_depth;
73 Window root_window;
74 int dxgrab = 0;
75 int usedga = 0;
76 int usexvidmode = 1;
77 int usexrandr = 1;
78 int use_xkb = 1;
79 int use_take_focus = 1;
80 int use_primary_selection = 0;
81 int managed_mode = 1;
82 int private_color_map = 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 BOOL desktop_dbl_buf = TRUE;
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_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_UTILITY",
138     "XdndAware",
139     "XdndEnter",
140     "XdndPosition",
141     "XdndStatus",
142     "XdndLeave",
143     "XdndFinished",
144     "XdndDrop",
145     "XdndActionCopy",
146     "XdndActionMove",
147     "XdndActionLink",
148     "XdndActionAsk",
149     "XdndActionPrivate",
150     "XdndSelection",
151     "XdndTarget",
152     "XdndTypeList",
153     "WCF_DIB",
154     "image/gif",
155     "text/html",
156     "text/plain",
157     "text/rtf",
158     "text/richtext"
159 };
160
161 /***********************************************************************
162  *              ignore_error
163  *
164  * Check if the X error is one we can ignore.
165  */
166 static inline BOOL ignore_error( Display *display, XErrorEvent *event )
167 {
168     if (event->request_code == X_SetInputFocus && event->error_code == BadMatch) return TRUE;
169
170     /* ignore a number of errors on gdi display caused by creating/destroying windows */
171     if (display == gdi_display)
172     {
173         if (event->error_code == BadDrawable || event->error_code == BadGC) return TRUE;
174 #ifdef HAVE_X11_EXTENSIONS_XRENDER_H
175         if (xrender_error_base)  /* check for XRender errors */
176         {
177             if (event->error_code == xrender_error_base + BadPicture) return TRUE;
178         }
179 #endif
180     }
181     return FALSE;
182 }
183
184
185 /***********************************************************************
186  *              X11DRV_expect_error
187  *
188  * Setup a callback function that will be called on an X error.  The
189  * callback must return non-zero if the error is the one it expected.
190  * This function acquires the x11 lock; X11DRV_check_error must be
191  * called in all cases to release it.
192  */
193 void X11DRV_expect_error( Display *display, x11drv_error_callback callback, void *arg )
194 {
195     wine_tsx11_lock();
196     err_callback         = callback;
197     err_callback_display = display;
198     err_callback_arg     = arg;
199     err_callback_result  = 0;
200     err_serial           = NextRequest(display);
201 }
202
203
204 /***********************************************************************
205  *              X11DRV_check_error
206  *
207  * Check if an expected X11 error occurred; return non-zero if yes.
208  * Also release the x11 lock obtained in X11DRV_expect_error.
209  * The caller is responsible for calling XSync first if necessary.
210  */
211 int X11DRV_check_error(void)
212 {
213     int ret;
214     err_callback = NULL;
215     ret = err_callback_result;
216     wine_tsx11_unlock();
217     return ret;
218 }
219
220
221 /***********************************************************************
222  *              error_handler
223  */
224 static int error_handler( Display *display, XErrorEvent *error_evt )
225 {
226     if (err_callback && display == err_callback_display &&
227         (long)(error_evt->serial - err_serial) >= 0)
228     {
229         if ((err_callback_result = err_callback( display, error_evt, err_callback_arg )))
230         {
231             TRACE( "got expected error %d req %d\n",
232                    error_evt->error_code, error_evt->request_code );
233             return 0;
234         }
235     }
236     if (ignore_error( display, error_evt ))
237     {
238         TRACE( "got ignored error %d req %d\n",
239                error_evt->error_code, error_evt->request_code );
240         return 0;
241     }
242     if (TRACE_ON(synchronous))
243     {
244         ERR( "X protocol error: serial=%ld, request_code=%d - breaking into debugger\n",
245              error_evt->serial, error_evt->request_code );
246         DebugBreak();  /* force an entry in the debugger */
247     }
248     old_error_handler( display, error_evt );
249     return 0;
250 }
251
252 /***********************************************************************
253  *              wine_tsx11_lock   (X11DRV.@)
254  */
255 void wine_tsx11_lock(void)
256 {
257     EnterCriticalSection( &X11DRV_CritSection );
258 }
259
260 /***********************************************************************
261  *              wine_tsx11_unlock   (X11DRV.@)
262  */
263 void wine_tsx11_unlock(void)
264 {
265     LeaveCriticalSection( &X11DRV_CritSection );
266 }
267
268
269 /***********************************************************************
270  *              get_config_key
271  *
272  * Get a config key from either the app-specific or the default config
273  */
274 inline static DWORD get_config_key( HKEY defkey, HKEY appkey, const char *name,
275                                     char *buffer, DWORD size )
276 {
277     if (appkey && !RegQueryValueExA( appkey, name, 0, NULL, (LPBYTE)buffer, &size )) return 0;
278     if (defkey && !RegQueryValueExA( defkey, name, 0, NULL, (LPBYTE)buffer, &size )) return 0;
279     return ERROR_FILE_NOT_FOUND;
280 }
281
282
283 /***********************************************************************
284  *              setup_options
285  *
286  * Setup the x11drv options.
287  */
288 static void setup_options(void)
289 {
290     char buffer[MAX_PATH+16];
291     HKEY hkey, appkey = 0;
292     DWORD len;
293
294     /* @@ Wine registry key: HKCU\Software\Wine\X11 Driver */
295     if (RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\X11 Driver", &hkey )) hkey = 0;
296
297     /* open the app-specific key */
298
299     len = (GetModuleFileNameA( 0, buffer, MAX_PATH ));
300     if (len && len < MAX_PATH)
301     {
302         HKEY tmpkey;
303         char *p, *appname = buffer;
304         if ((p = strrchr( appname, '/' ))) appname = p + 1;
305         if ((p = strrchr( appname, '\\' ))) appname = p + 1;
306         strcat( appname, "\\X11 Driver" );
307         /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\X11 Driver */
308         if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\AppDefaults", &tmpkey ))
309         {
310             if (RegOpenKeyA( tmpkey, appname, &appkey )) appkey = 0;
311             RegCloseKey( tmpkey );
312         }
313     }
314
315     if (!get_config_key( hkey, appkey, "Managed", buffer, sizeof(buffer) ))
316         managed_mode = IS_OPTION_TRUE( buffer[0] );
317
318     if (!get_config_key( hkey, appkey, "DXGrab", buffer, sizeof(buffer) ))
319         dxgrab = IS_OPTION_TRUE( buffer[0] );
320
321     if (!get_config_key( hkey, appkey, "UseDGA", buffer, sizeof(buffer) ))
322         usedga = 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, "DesktopDoubleBuffered", buffer, sizeof(buffer) ))
353         desktop_dbl_buf = IS_OPTION_TRUE( buffer[0] );
354
355     if (!get_config_key( hkey, appkey, "UseXIM", buffer, sizeof(buffer) ))
356         use_xim = IS_OPTION_TRUE( buffer[0] );
357
358     if (!get_config_key( hkey, appkey, "PrivateColorMap", buffer, sizeof(buffer) ))
359         private_color_map = IS_OPTION_TRUE( buffer[0] );
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 (!(display = XOpenDisplay( NULL ))) return FALSE;
389
390     fcntl( ConnectionNumber(display), F_SETFD, 1 ); /* set close on exec flag */
391     screen = DefaultScreenOfDisplay( display );
392     visual = DefaultVisual( display, DefaultScreen(display) );
393     root_window = DefaultRootWindow( display );
394     gdi_display = display;
395     old_error_handler = XSetErrorHandler( error_handler );
396
397     /* Initialize screen depth */
398
399     if (screen_depth)  /* depth specified */
400     {
401         int depth_count, i;
402         int *depth_list = XListDepths(display, DefaultScreen(display), &depth_count);
403         for (i = 0; i < depth_count; i++)
404             if (depth_list[i] == screen_depth) break;
405         XFree( depth_list );
406         if (i >= depth_count)
407         {
408             WARN( "invalid depth %d, using default\n", screen_depth );
409             screen_depth = 0;
410         }
411     }
412     if (!screen_depth) screen_depth = DefaultDepthOfScreen( screen );
413
414     /* If OpenGL is available, change the default visual, etc as necessary */
415     if (desktop_dbl_buf && (desktop_vi = X11DRV_setup_opengl_visual( display )))
416     {
417         visual       = desktop_vi->visual;
418         screen       = ScreenOfDisplay(display, desktop_vi->screen);
419         screen_depth = desktop_vi->depth;
420         XFree(desktop_vi);
421     }
422
423     XInternAtoms( display, (char **)atom_names, NB_XATOMS - FIRST_XATOM, False, X11DRV_Atoms );
424
425     if (TRACE_ON(synchronous)) XSynchronize( display, True );
426
427     screen_width  = WidthOfScreen( screen );
428     screen_height = HeightOfScreen( screen );
429
430     X11DRV_Settings_Init();
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         X11DRV_ResetSelectionOwner();
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 (TRACE_ON(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                                   0, &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     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 }