wined3d: Add the bulk of the GLSL string generation functions.
[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         X11DRV_ResetSelectionOwner();
461         CloseHandle( data->display_fd );
462         wine_tsx11_lock();
463         XCloseDisplay( data->display );
464         /* if (data->xim) XCloseIM( data->xim ); */ /* crashes Xlib */
465         wine_tsx11_unlock();
466         HeapFree( GetProcessHeap(), 0, data );
467     }
468 }
469
470
471 /***********************************************************************
472  *           X11DRV process termination routine
473  */
474 static void process_detach(void)
475 {
476 #ifdef HAVE_LIBXXF86DGA2
477     /* cleanup DGA2 */
478     X11DRV_XF86DGA2_Cleanup();
479 #endif
480 #ifdef HAVE_LIBXXF86VM
481     /* cleanup XVidMode */
482     X11DRV_XF86VM_Cleanup();
483 #endif
484     if(using_client_side_fonts)
485         X11DRV_XRender_Finalize();
486
487     /* cleanup GDI */
488     X11DRV_GDI_Finalize();
489
490     DeleteCriticalSection( &X11DRV_CritSection );
491     TlsFree( thread_data_tls_index );
492 }
493
494
495 /***********************************************************************
496  *           X11DRV thread initialisation routine
497  */
498 struct x11drv_thread_data *x11drv_init_thread_data(void)
499 {
500     struct x11drv_thread_data *data;
501
502     if (!(data = HeapAlloc( GetProcessHeap(), 0, sizeof(*data) )))
503     {
504         ERR( "could not create data\n" );
505         ExitProcess(1);
506     }
507     wine_tsx11_lock();
508     if (!(data->display = XOpenDisplay(NULL)))
509     {
510         wine_tsx11_unlock();
511         MESSAGE( "x11drv: Can't open display: %s\n", XDisplayName(NULL) );
512         MESSAGE( "Please ensure that your X server is running and that $DISPLAY is set correctly.\n" );
513         ExitProcess(1);
514     }
515
516     fcntl( ConnectionNumber(data->display), F_SETFD, 1 ); /* set close on exec flag */
517
518 #ifdef HAVE_XKB
519     if (use_xkb)
520     {
521         use_xkb = XkbUseExtension( data->display, NULL, NULL );
522         if (use_xkb) XkbSetDetectableAutoRepeat( data->display, True, NULL );
523     }
524 #endif
525
526     if (TRACE_ON(synchronous)) XSynchronize( data->display, True );
527     wine_tsx11_unlock();
528
529     if (use_xim && !(data->xim = X11DRV_SetupXIM( data->display, input_style )))
530         WARN("Input Method is not available\n");
531
532     if (wine_server_fd_to_handle( ConnectionNumber(data->display), GENERIC_READ | SYNCHRONIZE,
533                                   0, &data->display_fd ))
534     {
535         MESSAGE( "x11drv: Can't allocate handle for display fd\n" );
536         ExitProcess(1);
537     }
538     data->process_event_count = 0;
539     data->cursor = None;
540     data->cursor_window = None;
541     data->grab_window = None;
542     data->last_focus = 0;
543     data->selection_wnd = 0;
544     TlsSetValue( thread_data_tls_index, data );
545     if (desktop_tid) AttachThreadInput( GetCurrentThreadId(), desktop_tid, TRUE );
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 }