msi: Set the install state to INSTALLSTATE_LOCAL for components with compressed files.
[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 Window root_window;
73 int dxgrab = 0;
74 int usexvidmode = 1;
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 copy_default_colors = 128;
86 int alloc_system_colors = 256;
87 DWORD thread_data_tls_index = TLS_OUT_OF_INDEXES;
88 int xrender_error_base = 0;
89
90 static BOOL desktop_dbl_buf = TRUE;
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_WM_MOVERESIZE",
129     "_NET_WM_NAME",
130     "_NET_WM_PID",
131     "_NET_WM_PING",
132     "_NET_WM_STATE",
133     "_NET_WM_STATE_FULLSCREEN",
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
168     /* ignore a number of errors on gdi display caused by creating/destroying windows */
169     if (display == gdi_display)
170     {
171         if (event->error_code == BadDrawable || event->error_code == BadGC) return TRUE;
172 #ifdef HAVE_X11_EXTENSIONS_XRENDER_H
173         if (xrender_error_base)  /* check for XRender errors */
174         {
175             if (event->error_code == xrender_error_base + BadPicture) return TRUE;
176         }
177 #endif
178     }
179     return FALSE;
180 }
181
182
183 /***********************************************************************
184  *              X11DRV_expect_error
185  *
186  * Setup a callback function that will be called on an X error.  The
187  * callback must return non-zero if the error is the one it expected.
188  * This function acquires the x11 lock; X11DRV_check_error must be
189  * called in all cases to release it.
190  */
191 void X11DRV_expect_error( Display *display, x11drv_error_callback callback, void *arg )
192 {
193     wine_tsx11_lock();
194     err_callback         = callback;
195     err_callback_display = display;
196     err_callback_arg     = arg;
197     err_callback_result  = 0;
198     err_serial           = NextRequest(display);
199 }
200
201
202 /***********************************************************************
203  *              X11DRV_check_error
204  *
205  * Check if an expected X11 error occurred; return non-zero if yes.
206  * Also release the x11 lock obtained in X11DRV_expect_error.
207  * The caller is responsible for calling XSync first if necessary.
208  */
209 int X11DRV_check_error(void)
210 {
211     int ret;
212     err_callback = NULL;
213     ret = err_callback_result;
214     wine_tsx11_unlock();
215     return ret;
216 }
217
218
219 /***********************************************************************
220  *              error_handler
221  */
222 static int error_handler( Display *display, XErrorEvent *error_evt )
223 {
224     if (err_callback && display == err_callback_display &&
225         (long)(error_evt->serial - err_serial) >= 0)
226     {
227         if ((err_callback_result = err_callback( display, error_evt, err_callback_arg )))
228         {
229             TRACE( "got expected error %d req %d\n",
230                    error_evt->error_code, error_evt->request_code );
231             return 0;
232         }
233     }
234     if (ignore_error( display, error_evt ))
235     {
236         TRACE( "got ignored error %d req %d\n",
237                error_evt->error_code, error_evt->request_code );
238         return 0;
239     }
240     if (TRACE_ON(synchronous))
241     {
242         ERR( "X protocol error: serial=%ld, request_code=%d - breaking into debugger\n",
243              error_evt->serial, error_evt->request_code );
244         DebugBreak();  /* force an entry in the debugger */
245     }
246     old_error_handler( display, error_evt );
247     return 0;
248 }
249
250 /***********************************************************************
251  *              wine_tsx11_lock   (X11DRV.@)
252  */
253 void wine_tsx11_lock(void)
254 {
255     EnterCriticalSection( &X11DRV_CritSection );
256 }
257
258 /***********************************************************************
259  *              wine_tsx11_unlock   (X11DRV.@)
260  */
261 void wine_tsx11_unlock(void)
262 {
263     LeaveCriticalSection( &X11DRV_CritSection );
264 }
265
266
267 /***********************************************************************
268  *              get_config_key
269  *
270  * Get a config key from either the app-specific or the default config
271  */
272 inline static DWORD get_config_key( HKEY defkey, HKEY appkey, const char *name,
273                                     char *buffer, DWORD size )
274 {
275     if (appkey && !RegQueryValueExA( appkey, name, 0, NULL, (LPBYTE)buffer, &size )) return 0;
276     if (defkey && !RegQueryValueExA( defkey, name, 0, NULL, (LPBYTE)buffer, &size )) return 0;
277     return ERROR_FILE_NOT_FOUND;
278 }
279
280
281 /***********************************************************************
282  *              setup_options
283  *
284  * Setup the x11drv options.
285  */
286 static void setup_options(void)
287 {
288     char buffer[MAX_PATH+16];
289     HKEY hkey, appkey = 0;
290     DWORD len;
291
292     /* @@ Wine registry key: HKCU\Software\Wine\X11 Driver */
293     if (RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\X11 Driver", &hkey )) hkey = 0;
294
295     /* open the app-specific key */
296
297     len = (GetModuleFileNameA( 0, buffer, MAX_PATH ));
298     if (len && len < MAX_PATH)
299     {
300         HKEY tmpkey;
301         char *p, *appname = buffer;
302         if ((p = strrchr( appname, '/' ))) appname = p + 1;
303         if ((p = strrchr( appname, '\\' ))) appname = p + 1;
304         strcat( appname, "\\X11 Driver" );
305         /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\X11 Driver */
306         if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\AppDefaults", &tmpkey ))
307         {
308             if (RegOpenKeyA( tmpkey, appname, &appkey )) appkey = 0;
309             RegCloseKey( tmpkey );
310         }
311     }
312
313     if (!get_config_key( hkey, appkey, "Managed", buffer, sizeof(buffer) ))
314         managed_mode = IS_OPTION_TRUE( buffer[0] );
315
316     if (!get_config_key( hkey, appkey, "DXGrab", buffer, sizeof(buffer) ))
317         dxgrab = IS_OPTION_TRUE( buffer[0] );
318
319     if (!get_config_key( hkey, appkey, "UseXVidMode", buffer, sizeof(buffer) ))
320         usexvidmode = IS_OPTION_TRUE( buffer[0] );
321
322     if (!get_config_key( hkey, appkey, "UseXRandR", buffer, sizeof(buffer) ))
323         usexrandr = IS_OPTION_TRUE( buffer[0] );
324
325     if (!get_config_key( hkey, appkey, "UseTakeFocus", buffer, sizeof(buffer) ))
326         use_take_focus = IS_OPTION_TRUE( buffer[0] );
327
328     if (!get_config_key( hkey, appkey, "UsePrimarySelection", buffer, sizeof(buffer) ))
329         use_primary_selection = IS_OPTION_TRUE( buffer[0] );
330
331     screen_depth = 0;
332     if (!get_config_key( hkey, appkey, "ScreenDepth", buffer, sizeof(buffer) ))
333         screen_depth = atoi(buffer);
334
335     if (!get_config_key( hkey, appkey, "ClientSideWithCore", buffer, sizeof(buffer) ))
336         client_side_with_core = IS_OPTION_TRUE( buffer[0] );
337
338     if (!get_config_key( hkey, appkey, "ClientSideWithRender", buffer, sizeof(buffer) ))
339         client_side_with_render = IS_OPTION_TRUE( buffer[0] );
340
341     if (!get_config_key( hkey, appkey, "ClientSideAntiAliasWithCore", buffer, sizeof(buffer) ))
342         client_side_antialias_with_core = IS_OPTION_TRUE( buffer[0] );
343
344     if (!get_config_key( hkey, appkey, "ClientSideAntiAliasWithRender", buffer, sizeof(buffer) ))
345         client_side_antialias_with_render = IS_OPTION_TRUE( buffer[0] );
346
347     if (!get_config_key( hkey, appkey, "DesktopDoubleBuffered", buffer, sizeof(buffer) ))
348         desktop_dbl_buf = IS_OPTION_TRUE( buffer[0] );
349
350     if (!get_config_key( hkey, appkey, "UseXIM", buffer, sizeof(buffer) ))
351         use_xim = IS_OPTION_TRUE( buffer[0] );
352
353     if (!get_config_key( hkey, appkey, "PrivateColorMap", buffer, sizeof(buffer) ))
354         private_color_map = IS_OPTION_TRUE( buffer[0] );
355
356     if (!get_config_key( hkey, appkey, "CopyDefaultColors", buffer, sizeof(buffer) ))
357         copy_default_colors = atoi(buffer);
358
359     if (!get_config_key( hkey, appkey, "AllocSystemColors", buffer, sizeof(buffer) ))
360         alloc_system_colors = atoi(buffer);
361
362     get_config_key( hkey, appkey, "InputStyle", input_style, sizeof(input_style) );
363
364     if (appkey) RegCloseKey( appkey );
365     if (hkey) RegCloseKey( hkey );
366 }
367
368
369 /***********************************************************************
370  *           X11DRV process initialisation routine
371  */
372 static BOOL process_attach(void)
373 {
374     Display *display;
375     XVisualInfo *desktop_vi = NULL;
376
377     setup_options();
378
379     if ((thread_data_tls_index = TlsAlloc()) == TLS_OUT_OF_INDEXES) return FALSE;
380
381     /* Open display */
382
383     if (!(display = XOpenDisplay( NULL ))) return FALSE;
384
385     fcntl( ConnectionNumber(display), F_SETFD, 1 ); /* set close on exec flag */
386     screen = DefaultScreenOfDisplay( display );
387     visual = DefaultVisual( display, DefaultScreen(display) );
388     root_window = DefaultRootWindow( display );
389     gdi_display = display;
390     old_error_handler = XSetErrorHandler( error_handler );
391
392     /* Initialize screen depth */
393
394     if (screen_depth)  /* depth specified */
395     {
396         int depth_count, i;
397         int *depth_list = XListDepths(display, DefaultScreen(display), &depth_count);
398         for (i = 0; i < depth_count; i++)
399             if (depth_list[i] == screen_depth) break;
400         XFree( depth_list );
401         if (i >= depth_count)
402         {
403             WARN( "invalid depth %d, using default\n", screen_depth );
404             screen_depth = 0;
405         }
406     }
407     if (!screen_depth) screen_depth = DefaultDepthOfScreen( screen );
408
409     /* If OpenGL is available, change the default visual, etc as necessary */
410     if (desktop_dbl_buf && (desktop_vi = X11DRV_setup_opengl_visual( display )))
411     {
412         visual       = desktop_vi->visual;
413         screen       = ScreenOfDisplay(display, desktop_vi->screen);
414         screen_depth = desktop_vi->depth;
415         XFree(desktop_vi);
416     }
417
418     XInternAtoms( display, (char **)atom_names, NB_XATOMS - FIRST_XATOM, False, X11DRV_Atoms );
419
420     if (TRACE_ON(synchronous)) XSynchronize( display, True );
421
422     screen_width  = WidthOfScreen( screen );
423     screen_height = HeightOfScreen( screen );
424
425     X11DRV_Settings_Init();
426
427 #ifdef HAVE_LIBXXF86VM
428     /* initialize XVidMode */
429     X11DRV_XF86VM_Init();
430 #endif
431 #ifdef HAVE_LIBXRANDR
432     /* initialize XRandR */
433     X11DRV_XRandR_Init();
434 #endif
435
436     X11DRV_InitKeyboard();
437     X11DRV_InitClipboard();
438
439     return TRUE;
440 }
441
442
443 /***********************************************************************
444  *           X11DRV thread termination routine
445  */
446 static void thread_detach(void)
447 {
448     struct x11drv_thread_data *data = TlsGetValue( thread_data_tls_index );
449
450     if (data)
451     {
452         X11DRV_ResetSelectionOwner();
453         CloseHandle( data->display_fd );
454         wine_tsx11_lock();
455         XCloseDisplay( data->display );
456         /* if (data->xim) XCloseIM( data->xim ); */ /* crashes Xlib */
457         wine_tsx11_unlock();
458         HeapFree( GetProcessHeap(), 0, data );
459     }
460 }
461
462
463 /***********************************************************************
464  *           X11DRV process termination routine
465  */
466 static void process_detach(void)
467 {
468 #ifdef HAVE_LIBXXF86VM
469     /* cleanup XVidMode */
470     X11DRV_XF86VM_Cleanup();
471 #endif
472     if(using_client_side_fonts)
473         X11DRV_XRender_Finalize();
474
475     /* cleanup GDI */
476     X11DRV_GDI_Finalize();
477
478     DeleteCriticalSection( &X11DRV_CritSection );
479     TlsFree( thread_data_tls_index );
480 }
481
482
483 /***********************************************************************
484  *           X11DRV thread initialisation routine
485  */
486 struct x11drv_thread_data *x11drv_init_thread_data(void)
487 {
488     struct x11drv_thread_data *data;
489
490     if (!(data = HeapAlloc( GetProcessHeap(), 0, sizeof(*data) )))
491     {
492         ERR( "could not create data\n" );
493         ExitProcess(1);
494     }
495     wine_tsx11_lock();
496     if (!(data->display = XOpenDisplay(NULL)))
497     {
498         wine_tsx11_unlock();
499         MESSAGE( "x11drv: Can't open display: %s\n", XDisplayName(NULL) );
500         MESSAGE( "Please ensure that your X server is running and that $DISPLAY is set correctly.\n" );
501         ExitProcess(1);
502     }
503
504     fcntl( ConnectionNumber(data->display), F_SETFD, 1 ); /* set close on exec flag */
505
506 #ifdef HAVE_XKB
507     if (use_xkb)
508     {
509         use_xkb = XkbUseExtension( data->display, NULL, NULL );
510         if (use_xkb) XkbSetDetectableAutoRepeat( data->display, True, NULL );
511     }
512 #endif
513
514     if (TRACE_ON(synchronous)) XSynchronize( data->display, True );
515     wine_tsx11_unlock();
516
517     if (use_xim && !(data->xim = X11DRV_SetupXIM( data->display, input_style )))
518         WARN("Input Method is not available\n");
519
520     if (wine_server_fd_to_handle( ConnectionNumber(data->display), GENERIC_READ | SYNCHRONIZE,
521                                   0, &data->display_fd ))
522     {
523         MESSAGE( "x11drv: Can't allocate handle for display fd\n" );
524         ExitProcess(1);
525     }
526     data->process_event_count = 0;
527     data->cursor = None;
528     data->cursor_window = None;
529     data->grab_window = None;
530     data->last_focus = 0;
531     data->selection_wnd = 0;
532     TlsSetValue( thread_data_tls_index, data );
533     return data;
534 }
535
536
537 /***********************************************************************
538  *           X11DRV initialisation routine
539  */
540 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
541 {
542     BOOL ret = TRUE;
543
544     switch(reason)
545     {
546     case DLL_PROCESS_ATTACH:
547         ret = process_attach();
548         break;
549     case DLL_THREAD_DETACH:
550         thread_detach();
551         break;
552     case DLL_PROCESS_DETACH:
553         process_detach();
554         break;
555     }
556     return ret;
557 }
558
559 /***********************************************************************
560  *              GetScreenSaveActive (X11DRV.@)
561  *
562  * Returns the active status of the screen saver
563  */
564 BOOL X11DRV_GetScreenSaveActive(void)
565 {
566     int timeout, temp;
567     wine_tsx11_lock();
568     XGetScreenSaver(gdi_display, &timeout, &temp, &temp, &temp);
569     wine_tsx11_unlock();
570     return timeout != 0;
571 }
572
573 /***********************************************************************
574  *              SetScreenSaveActive (X11DRV.@)
575  *
576  * Activate/Deactivate the screen saver
577  */
578 void X11DRV_SetScreenSaveActive(BOOL bActivate)
579 {
580     int timeout, interval, prefer_blanking, allow_exposures;
581     static int last_timeout = 15 * 60;
582
583     wine_tsx11_lock();
584     XGetScreenSaver(gdi_display, &timeout, &interval, &prefer_blanking,
585                     &allow_exposures);
586     if (timeout) last_timeout = timeout;
587
588     timeout = bActivate ? last_timeout : 0;
589     XSetScreenSaver(gdi_display, timeout, interval, prefer_blanking,
590                     allow_exposures);
591     wine_tsx11_unlock();
592 }