push ac694015ba9a1d7cf8fc6346c6e51d4c35a62962
[wine/hacks.git] / dlls / winex11.drv / x11drv_main.c
blob41c866c3a37f9d5215d32b7d4a1a841505c095a0
1 /*
2 * X11DRV initialization code
4 * Copyright 1998 Patrik Stridvall
5 * Copyright 2000 Alexandre Julliard
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.
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.
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
22 #include "config.h"
23 #include "wine/port.h"
25 #include <fcntl.h>
26 #include <stdarg.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #ifdef HAVE_SYS_TIME_H
31 # include <sys/time.h>
32 #endif
33 #ifdef HAVE_UNISTD_H
34 # include <unistd.h>
35 #endif
36 #include <X11/cursorfont.h>
37 #include <X11/Xlib.h>
38 #ifdef HAVE_XKB
39 #include <X11/XKBlib.h>
40 #endif
41 #ifdef HAVE_X11_EXTENSIONS_XRENDER_H
42 #include <X11/extensions/Xrender.h>
43 #endif
45 #include "windef.h"
46 #include "winbase.h"
47 #include "winreg.h"
49 #include "x11drv.h"
50 #include "xvidmode.h"
51 #include "xrandr.h"
52 #include "xcomposite.h"
53 #include "wine/server.h"
54 #include "wine/debug.h"
55 #include "wine/library.h"
57 WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
58 WINE_DECLARE_DEBUG_CHANNEL(synchronous);
60 static CRITICAL_SECTION X11DRV_CritSection;
61 static CRITICAL_SECTION_DEBUG critsect_debug =
63 0, 0, &X11DRV_CritSection,
64 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
65 0, 0, { (DWORD_PTR)(__FILE__ ": X11DRV_CritSection") }
67 static CRITICAL_SECTION X11DRV_CritSection = { &critsect_debug, -1, 0, 0, 0, 0 };
69 Screen *screen;
70 Visual *visual;
71 unsigned int screen_width;
72 unsigned int screen_height;
73 unsigned int screen_bpp;
74 unsigned int screen_depth;
75 RECT virtual_screen_rect;
76 Window root_window;
77 int dxgrab = 0;
78 int usexvidmode = 1;
79 int usexrandr = 1;
80 int usexcomposite = 1;
81 int use_xkb = 1;
82 int use_take_focus = 1;
83 int use_primary_selection = 0;
84 int managed_mode = 1;
85 int decorated_mode = 1;
86 int private_color_map = 0;
87 int primary_monitor = 0;
88 int client_side_with_core = 1;
89 int client_side_with_render = 1;
90 int client_side_antialias_with_core = 1;
91 int client_side_antialias_with_render = 1;
92 int copy_default_colors = 128;
93 int alloc_system_colors = 256;
94 DWORD thread_data_tls_index = TLS_OUT_OF_INDEXES;
95 int xrender_error_base = 0;
96 HMODULE x11drv_module = 0;
98 static x11drv_error_callback err_callback; /* current callback for error */
99 static Display *err_callback_display; /* display callback is set for */
100 static void *err_callback_arg; /* error callback argument */
101 static int err_callback_result; /* error callback result */
102 static unsigned long err_serial; /* serial number of first request */
103 static int (*old_error_handler)( Display *, XErrorEvent * );
104 static int use_xim = 1;
105 static char input_style[20];
107 #define IS_OPTION_TRUE(ch) \
108 ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1')
109 #define IS_OPTION_FALSE(ch) \
110 ((ch) == 'n' || (ch) == 'N' || (ch) == 'f' || (ch) == 'F' || (ch) == '0')
112 Atom X11DRV_Atoms[NB_XATOMS - FIRST_XATOM];
114 static const char * const atom_names[NB_XATOMS - FIRST_XATOM] =
116 "CLIPBOARD",
117 "COMPOUND_TEXT",
118 "INCR",
119 "MULTIPLE",
120 "SELECTION_DATA",
121 "TARGETS",
122 "TEXT",
123 "UTF8_STRING",
124 "RAW_ASCENT",
125 "RAW_DESCENT",
126 "RAW_CAP_HEIGHT",
127 "WM_PROTOCOLS",
128 "WM_DELETE_WINDOW",
129 "WM_STATE",
130 "WM_TAKE_FOCUS",
131 "DndProtocol",
132 "DndSelection",
133 "_ICC_PROFILE",
134 "_MOTIF_WM_HINTS",
135 "_NET_STARTUP_INFO_BEGIN",
136 "_NET_STARTUP_INFO",
137 "_NET_SUPPORTED",
138 "_NET_SYSTEM_TRAY_OPCODE",
139 "_NET_SYSTEM_TRAY_S0",
140 "_NET_WM_MOVERESIZE",
141 "_NET_WM_NAME",
142 "_NET_WM_PID",
143 "_NET_WM_PING",
144 "_NET_WM_STATE",
145 "_NET_WM_STATE_ABOVE",
146 "_NET_WM_STATE_FULLSCREEN",
147 "_NET_WM_STATE_MAXIMIZED_HORZ",
148 "_NET_WM_STATE_MAXIMIZED_VERT",
149 "_NET_WM_STATE_SKIP_PAGER",
150 "_NET_WM_STATE_SKIP_TASKBAR",
151 "_NET_WM_WINDOW_OPACITY",
152 "_NET_WM_WINDOW_TYPE",
153 "_NET_WM_WINDOW_TYPE_DIALOG",
154 "_NET_WM_WINDOW_TYPE_NORMAL",
155 "_NET_WM_WINDOW_TYPE_UTILITY",
156 "_NET_WORKAREA",
157 "_XEMBED_INFO",
158 "XdndAware",
159 "XdndEnter",
160 "XdndPosition",
161 "XdndStatus",
162 "XdndLeave",
163 "XdndFinished",
164 "XdndDrop",
165 "XdndActionCopy",
166 "XdndActionMove",
167 "XdndActionLink",
168 "XdndActionAsk",
169 "XdndActionPrivate",
170 "XdndSelection",
171 "XdndTarget",
172 "XdndTypeList",
173 "WCF_DIB",
174 "image/gif",
175 "text/html",
176 "text/plain",
177 "text/rtf",
178 "text/richtext",
179 "text/uri-list"
182 /***********************************************************************
183 * ignore_error
185 * Check if the X error is one we can ignore.
187 static inline BOOL ignore_error( Display *display, XErrorEvent *event )
189 if (event->request_code == X_SetInputFocus && event->error_code == BadMatch) return TRUE;
191 /* ignore a number of errors on gdi display caused by creating/destroying windows */
192 if (display == gdi_display)
194 if (event->error_code == BadDrawable || event->error_code == BadGC) return TRUE;
195 #ifdef HAVE_X11_EXTENSIONS_XRENDER_H
196 if (xrender_error_base) /* check for XRender errors */
198 if (event->error_code == xrender_error_base + BadPicture) return TRUE;
200 #endif
202 return FALSE;
206 /***********************************************************************
207 * X11DRV_expect_error
209 * Setup a callback function that will be called on an X error. The
210 * callback must return non-zero if the error is the one it expected.
211 * This function acquires the x11 lock; X11DRV_check_error must be
212 * called in all cases to release it.
214 void X11DRV_expect_error( Display *display, x11drv_error_callback callback, void *arg )
216 wine_tsx11_lock();
217 err_callback = callback;
218 err_callback_display = display;
219 err_callback_arg = arg;
220 err_callback_result = 0;
221 err_serial = NextRequest(display);
225 /***********************************************************************
226 * X11DRV_check_error
228 * Check if an expected X11 error occurred; return non-zero if yes.
229 * Also release the x11 lock obtained in X11DRV_expect_error.
230 * The caller is responsible for calling XSync first if necessary.
232 int X11DRV_check_error(void)
234 int ret;
235 err_callback = NULL;
236 ret = err_callback_result;
237 wine_tsx11_unlock();
238 return ret;
242 /***********************************************************************
243 * error_handler
245 static int error_handler( Display *display, XErrorEvent *error_evt )
247 if (err_callback && display == err_callback_display &&
248 (long)(error_evt->serial - err_serial) >= 0)
250 if ((err_callback_result = err_callback( display, error_evt, err_callback_arg )))
252 TRACE( "got expected error %d req %d\n",
253 error_evt->error_code, error_evt->request_code );
254 return 0;
257 if (ignore_error( display, error_evt ))
259 TRACE( "got ignored error %d req %d\n",
260 error_evt->error_code, error_evt->request_code );
261 return 0;
263 if (TRACE_ON(synchronous))
265 ERR( "X protocol error: serial=%ld, request_code=%d - breaking into debugger\n",
266 error_evt->serial, error_evt->request_code );
267 DebugBreak(); /* force an entry in the debugger */
269 old_error_handler( display, error_evt );
270 return 0;
273 /***********************************************************************
274 * wine_tsx11_lock (X11DRV.@)
276 void CDECL wine_tsx11_lock(void)
278 EnterCriticalSection( &X11DRV_CritSection );
281 /***********************************************************************
282 * wine_tsx11_unlock (X11DRV.@)
284 void CDECL wine_tsx11_unlock(void)
286 LeaveCriticalSection( &X11DRV_CritSection );
290 /***********************************************************************
291 * depth_to_bpp
293 * Convert X11-reported depth to the BPP value that Windows apps expect to see.
295 unsigned int depth_to_bpp( unsigned int depth )
297 switch (depth)
299 case 1:
300 case 8:
301 return depth;
302 case 15:
303 case 16:
304 return 16;
305 case 24:
306 /* This is not necessarily right. X11 always has 24 bits per pixel, but it can run
307 * with 24 bit framebuffers and 32 bit framebuffers. It doesn't make any difference
308 * for windowing, but gl applications can get visuals with alpha channels. So we
309 * should check the framebuffer and/or opengl formats available to find out what the
310 * framebuffer actually does
312 case 32:
313 return 32;
314 default:
315 FIXME( "Unexpected X11 depth %d bpp, what to report to app?\n", depth );
316 return depth;
321 /***********************************************************************
322 * get_config_key
324 * Get a config key from either the app-specific or the default config
326 static inline DWORD get_config_key( HKEY defkey, HKEY appkey, const char *name,
327 char *buffer, DWORD size )
329 if (appkey && !RegQueryValueExA( appkey, name, 0, NULL, (LPBYTE)buffer, &size )) return 0;
330 if (defkey && !RegQueryValueExA( defkey, name, 0, NULL, (LPBYTE)buffer, &size )) return 0;
331 return ERROR_FILE_NOT_FOUND;
335 /***********************************************************************
336 * setup_options
338 * Setup the x11drv options.
340 static void setup_options(void)
342 char buffer[MAX_PATH+16];
343 HKEY hkey, appkey = 0;
344 DWORD len;
346 /* @@ Wine registry key: HKCU\Software\Wine\X11 Driver */
347 if (RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\X11 Driver", &hkey )) hkey = 0;
349 /* open the app-specific key */
351 len = (GetModuleFileNameA( 0, buffer, MAX_PATH ));
352 if (len && len < MAX_PATH)
354 HKEY tmpkey;
355 char *p, *appname = buffer;
356 if ((p = strrchr( appname, '/' ))) appname = p + 1;
357 if ((p = strrchr( appname, '\\' ))) appname = p + 1;
358 strcat( appname, "\\X11 Driver" );
359 /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\X11 Driver */
360 if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\AppDefaults", &tmpkey ))
362 if (RegOpenKeyA( tmpkey, appname, &appkey )) appkey = 0;
363 RegCloseKey( tmpkey );
367 if (!get_config_key( hkey, appkey, "Managed", buffer, sizeof(buffer) ))
368 managed_mode = IS_OPTION_TRUE( buffer[0] );
370 if (!get_config_key( hkey, appkey, "Decorated", buffer, sizeof(buffer) ))
371 decorated_mode = IS_OPTION_TRUE( buffer[0] );
373 if (!get_config_key( hkey, appkey, "DXGrab", buffer, sizeof(buffer) ))
374 dxgrab = IS_OPTION_TRUE( buffer[0] );
376 if (!get_config_key( hkey, appkey, "UseXVidMode", buffer, sizeof(buffer) ))
377 usexvidmode = IS_OPTION_TRUE( buffer[0] );
379 if (!get_config_key( hkey, appkey, "UseXRandR", buffer, sizeof(buffer) ))
380 usexrandr = IS_OPTION_TRUE( buffer[0] );
382 if (!get_config_key( hkey, appkey, "UseTakeFocus", buffer, sizeof(buffer) ))
383 use_take_focus = IS_OPTION_TRUE( buffer[0] );
385 if (!get_config_key( hkey, appkey, "UsePrimarySelection", buffer, sizeof(buffer) ))
386 use_primary_selection = IS_OPTION_TRUE( buffer[0] );
388 screen_depth = 0;
389 if (!get_config_key( hkey, appkey, "ScreenDepth", buffer, sizeof(buffer) ))
390 screen_depth = atoi(buffer);
392 if (!get_config_key( hkey, appkey, "ClientSideWithCore", buffer, sizeof(buffer) ))
393 client_side_with_core = IS_OPTION_TRUE( buffer[0] );
395 if (!get_config_key( hkey, appkey, "ClientSideWithRender", buffer, sizeof(buffer) ))
396 client_side_with_render = IS_OPTION_TRUE( buffer[0] );
398 if (!get_config_key( hkey, appkey, "ClientSideAntiAliasWithCore", buffer, sizeof(buffer) ))
399 client_side_antialias_with_core = IS_OPTION_TRUE( buffer[0] );
401 if (!get_config_key( hkey, appkey, "ClientSideAntiAliasWithRender", buffer, sizeof(buffer) ))
402 client_side_antialias_with_render = IS_OPTION_TRUE( buffer[0] );
404 if (!get_config_key( hkey, appkey, "UseXIM", buffer, sizeof(buffer) ))
405 use_xim = IS_OPTION_TRUE( buffer[0] );
407 if (!get_config_key( hkey, appkey, "PrivateColorMap", buffer, sizeof(buffer) ))
408 private_color_map = IS_OPTION_TRUE( buffer[0] );
410 if (!get_config_key( hkey, appkey, "PrimaryMonitor", buffer, sizeof(buffer) ))
411 primary_monitor = atoi( buffer );
413 if (!get_config_key( hkey, appkey, "CopyDefaultColors", buffer, sizeof(buffer) ))
414 copy_default_colors = atoi(buffer);
416 if (!get_config_key( hkey, appkey, "AllocSystemColors", buffer, sizeof(buffer) ))
417 alloc_system_colors = atoi(buffer);
419 get_config_key( hkey, appkey, "InputStyle", input_style, sizeof(input_style) );
421 if (appkey) RegCloseKey( appkey );
422 if (hkey) RegCloseKey( hkey );
425 #ifdef SONAME_LIBXCOMPOSITE
427 #define MAKE_FUNCPTR(f) typeof(f) * p##f;
428 MAKE_FUNCPTR(XCompositeQueryExtension)
429 MAKE_FUNCPTR(XCompositeQueryVersion)
430 MAKE_FUNCPTR(XCompositeVersion)
431 MAKE_FUNCPTR(XCompositeRedirectWindow)
432 MAKE_FUNCPTR(XCompositeRedirectSubwindows)
433 MAKE_FUNCPTR(XCompositeUnredirectWindow)
434 MAKE_FUNCPTR(XCompositeUnredirectSubwindows)
435 MAKE_FUNCPTR(XCompositeCreateRegionFromBorderClip)
436 MAKE_FUNCPTR(XCompositeNameWindowPixmap)
437 #undef MAKE_FUNCPTR
439 static int xcomp_event_base;
440 static int xcomp_error_base;
442 static void X11DRV_XComposite_Init(void)
444 void *xcomposite_handle = wine_dlopen(SONAME_LIBXCOMPOSITE, RTLD_NOW, NULL, 0);
445 if (!xcomposite_handle)
447 TRACE("Unable to open %s, XComposite disabled\n", SONAME_LIBXCOMPOSITE);
448 usexcomposite = 0;
449 return;
452 #define LOAD_FUNCPTR(f) \
453 if((p##f = wine_dlsym(xcomposite_handle, #f, NULL, 0)) == NULL) \
454 goto sym_not_found;
455 LOAD_FUNCPTR(XCompositeQueryExtension)
456 LOAD_FUNCPTR(XCompositeQueryVersion)
457 LOAD_FUNCPTR(XCompositeVersion)
458 LOAD_FUNCPTR(XCompositeRedirectWindow)
459 LOAD_FUNCPTR(XCompositeRedirectSubwindows)
460 LOAD_FUNCPTR(XCompositeUnredirectWindow)
461 LOAD_FUNCPTR(XCompositeUnredirectSubwindows)
462 LOAD_FUNCPTR(XCompositeCreateRegionFromBorderClip)
463 LOAD_FUNCPTR(XCompositeNameWindowPixmap)
464 #undef LOAD_FUNCPTR
466 if(!pXCompositeQueryExtension(gdi_display, &xcomp_event_base,
467 &xcomp_error_base)) {
468 TRACE("XComposite extension could not be queried; disabled\n");
469 wine_dlclose(xcomposite_handle, NULL, 0);
470 xcomposite_handle = NULL;
471 usexcomposite = 0;
472 return;
474 TRACE("XComposite is up and running error_base = %d\n", xcomp_error_base);
475 return;
477 sym_not_found:
478 TRACE("Unable to load function pointers from %s, XComposite disabled\n", SONAME_LIBXCOMPOSITE);
479 wine_dlclose(xcomposite_handle, NULL, 0);
480 xcomposite_handle = NULL;
481 usexcomposite = 0;
483 #endif /* defined(SONAME_LIBXCOMPOSITE) */
486 /***********************************************************************
487 * X11DRV process initialisation routine
489 static BOOL process_attach(void)
491 Display *display;
493 setup_options();
495 if ((thread_data_tls_index = TlsAlloc()) == TLS_OUT_OF_INDEXES) return FALSE;
497 /* Open display */
499 if (!(display = XOpenDisplay( NULL ))) return FALSE;
501 fcntl( ConnectionNumber(display), F_SETFD, 1 ); /* set close on exec flag */
502 screen = DefaultScreenOfDisplay( display );
503 visual = DefaultVisual( display, DefaultScreen(display) );
504 root_window = DefaultRootWindow( display );
505 gdi_display = display;
506 old_error_handler = XSetErrorHandler( error_handler );
508 /* Initialize screen depth */
510 if (screen_depth) /* depth specified */
512 int depth_count, i;
513 int *depth_list = XListDepths(display, DefaultScreen(display), &depth_count);
514 for (i = 0; i < depth_count; i++)
515 if (depth_list[i] == screen_depth) break;
516 XFree( depth_list );
517 if (i >= depth_count)
519 WARN( "invalid depth %d, using default\n", screen_depth );
520 screen_depth = 0;
523 if (!screen_depth) screen_depth = DefaultDepthOfScreen( screen );
524 screen_bpp = depth_to_bpp( screen_depth );
526 XInternAtoms( display, (char **)atom_names, NB_XATOMS - FIRST_XATOM, False, X11DRV_Atoms );
528 if (TRACE_ON(synchronous)) XSynchronize( display, True );
530 xinerama_init( WidthOfScreen(screen), HeightOfScreen(screen) );
531 X11DRV_Settings_Init();
533 #ifdef SONAME_LIBXXF86VM
534 /* initialize XVidMode */
535 X11DRV_XF86VM_Init();
536 #endif
537 #ifdef SONAME_LIBXRANDR
538 /* initialize XRandR */
539 X11DRV_XRandR_Init();
540 #endif
541 #ifdef SONAME_LIBXCOMPOSITE
542 X11DRV_XComposite_Init();
543 #endif
545 #ifdef HAVE_XKB
546 if (use_xkb) use_xkb = XkbUseExtension( gdi_display, NULL, NULL );
547 #endif
548 X11DRV_InitKeyboard( gdi_display );
549 X11DRV_InitClipboard();
550 if (use_xim) use_xim = X11DRV_InitXIM( input_style );
552 return TRUE;
556 /***********************************************************************
557 * X11DRV thread termination routine
559 static void thread_detach(void)
561 struct x11drv_thread_data *data = TlsGetValue( thread_data_tls_index );
563 if (data)
565 X11DRV_ResetSelectionOwner();
566 wine_tsx11_lock();
567 if (data->xim) XCloseIM( data->xim );
568 if (data->font_set) XFreeFontSet( data->display, data->font_set );
569 XCloseDisplay( data->display );
570 wine_tsx11_unlock();
571 HeapFree( GetProcessHeap(), 0, data );
576 /***********************************************************************
577 * X11DRV process termination routine
579 static void process_detach(void)
581 #ifdef SONAME_LIBXXF86VM
582 /* cleanup XVidMode */
583 X11DRV_XF86VM_Cleanup();
584 #endif
585 if(using_client_side_fonts)
586 X11DRV_XRender_Finalize();
588 /* cleanup GDI */
589 X11DRV_GDI_Finalize();
590 X11DRV_OpenGL_Cleanup();
592 IME_UnregisterClasses();
593 DeleteCriticalSection( &X11DRV_CritSection );
594 TlsFree( thread_data_tls_index );
598 /* store the display fd into the message queue */
599 static void set_queue_display_fd( Display *display )
601 HANDLE handle;
602 int ret;
604 if (wine_server_fd_to_handle( ConnectionNumber(display), GENERIC_READ | SYNCHRONIZE, 0, &handle ))
606 MESSAGE( "x11drv: Can't allocate handle for display fd\n" );
607 ExitProcess(1);
609 SERVER_START_REQ( set_queue_fd )
611 req->handle = wine_server_obj_handle( handle );
612 ret = wine_server_call( req );
614 SERVER_END_REQ;
615 if (ret)
617 MESSAGE( "x11drv: Can't store handle for display fd\n" );
618 ExitProcess(1);
620 CloseHandle( handle );
624 /***********************************************************************
625 * X11DRV thread initialisation routine
627 struct x11drv_thread_data *x11drv_init_thread_data(void)
629 struct x11drv_thread_data *data = x11drv_thread_data();
631 if (data) return data;
633 if (!(data = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*data) )))
635 ERR( "could not create data\n" );
636 ExitProcess(1);
638 wine_tsx11_lock();
639 if (!(data->display = XOpenDisplay(NULL)))
641 wine_tsx11_unlock();
642 MESSAGE( "x11drv: Can't open display: %s\n", XDisplayName(NULL) );
643 MESSAGE( "Please ensure that your X server is running and that $DISPLAY is set correctly.\n" );
644 ExitProcess(1);
647 fcntl( ConnectionNumber(data->display), F_SETFD, 1 ); /* set close on exec flag */
649 #ifdef HAVE_XKB
650 if (use_xkb && XkbUseExtension( data->display, NULL, NULL ))
651 XkbSetDetectableAutoRepeat( data->display, True, NULL );
652 #endif
654 if (TRACE_ON(synchronous)) XSynchronize( data->display, True );
655 wine_tsx11_unlock();
657 set_queue_display_fd( data->display );
658 TlsSetValue( thread_data_tls_index, data );
660 if (use_xim) X11DRV_SetupXIM();
661 X11DRV_SetCursor( NULL );
663 return data;
667 /***********************************************************************
668 * X11DRV initialisation routine
670 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
672 BOOL ret = TRUE;
674 switch(reason)
676 case DLL_PROCESS_ATTACH:
677 x11drv_module = hinst;
678 ret = process_attach();
679 break;
680 case DLL_THREAD_DETACH:
681 thread_detach();
682 break;
683 case DLL_PROCESS_DETACH:
684 process_detach();
685 break;
687 return ret;
690 /***********************************************************************
691 * GetScreenSaveActive (X11DRV.@)
693 * Returns the active status of the screen saver
695 BOOL CDECL X11DRV_GetScreenSaveActive(void)
697 int timeout, temp;
698 wine_tsx11_lock();
699 XGetScreenSaver(gdi_display, &timeout, &temp, &temp, &temp);
700 wine_tsx11_unlock();
701 return timeout != 0;
704 /***********************************************************************
705 * SetScreenSaveActive (X11DRV.@)
707 * Activate/Deactivate the screen saver
709 void CDECL X11DRV_SetScreenSaveActive(BOOL bActivate)
711 int timeout, interval, prefer_blanking, allow_exposures;
712 static int last_timeout = 15 * 60;
714 wine_tsx11_lock();
715 XGetScreenSaver(gdi_display, &timeout, &interval, &prefer_blanking,
716 &allow_exposures);
717 if (timeout) last_timeout = timeout;
719 timeout = bActivate ? last_timeout : 0;
720 XSetScreenSaver(gdi_display, timeout, interval, prefer_blanking,
721 allow_exposures);
722 wine_tsx11_unlock();