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