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