winex11: Abstract the depth->bpp conversion and use it in X11DRV_DIB_CreateDIBFromPixmap.
[wine/multimedia.git] / dlls / winex11.drv / x11drv_main.c
blob6f682c2a9e5554ae51bda6ab6ada51ac4168d471
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 private_color_map = 0;
86 int primary_monitor = 0;
87 int client_side_with_core = 1;
88 int client_side_with_render = 1;
89 int client_side_antialias_with_core = 1;
90 int client_side_antialias_with_render = 1;
91 int copy_default_colors = 128;
92 int alloc_system_colors = 256;
93 DWORD thread_data_tls_index = TLS_OUT_OF_INDEXES;
94 int xrender_error_base = 0;
96 static x11drv_error_callback err_callback; /* current callback for error */
97 static Display *err_callback_display; /* display callback is set for */
98 static void *err_callback_arg; /* error callback argument */
99 static int err_callback_result; /* error callback result */
100 static unsigned long err_serial; /* serial number of first request */
101 static int (*old_error_handler)( Display *, XErrorEvent * );
102 static int use_xim = 1;
103 static char input_style[20];
105 #define IS_OPTION_TRUE(ch) \
106 ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1')
107 #define IS_OPTION_FALSE(ch) \
108 ((ch) == 'n' || (ch) == 'N' || (ch) == 'f' || (ch) == 'F' || (ch) == '0')
110 Atom X11DRV_Atoms[NB_XATOMS - FIRST_XATOM];
112 static const char * const atom_names[NB_XATOMS - FIRST_XATOM] =
114 "CLIPBOARD",
115 "COMPOUND_TEXT",
116 "MULTIPLE",
117 "SELECTION_DATA",
118 "TARGETS",
119 "TEXT",
120 "UTF8_STRING",
121 "RAW_ASCENT",
122 "RAW_DESCENT",
123 "RAW_CAP_HEIGHT",
124 "WM_PROTOCOLS",
125 "WM_DELETE_WINDOW",
126 "WM_TAKE_FOCUS",
127 "KWM_DOCKWINDOW",
128 "DndProtocol",
129 "DndSelection",
130 "_MOTIF_WM_HINTS",
131 "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR",
132 "_NET_SYSTEM_TRAY_OPCODE",
133 "_NET_SYSTEM_TRAY_S0",
134 "_NET_WM_MOVERESIZE",
135 "_NET_WM_NAME",
136 "_NET_WM_PID",
137 "_NET_WM_PING",
138 "_NET_WM_STATE",
139 "_NET_WM_STATE_ABOVE",
140 "_NET_WM_STATE_FULLSCREEN",
141 "_NET_WM_STATE_SKIP_PAGER",
142 "_NET_WM_STATE_SKIP_TASKBAR",
143 "_NET_WM_WINDOW_TYPE",
144 "_NET_WM_WINDOW_TYPE_DIALOG",
145 "_NET_WM_WINDOW_TYPE_NORMAL",
146 "_NET_WM_WINDOW_TYPE_UTILITY",
147 "_XEMBED_INFO",
148 "XdndAware",
149 "XdndEnter",
150 "XdndPosition",
151 "XdndStatus",
152 "XdndLeave",
153 "XdndFinished",
154 "XdndDrop",
155 "XdndActionCopy",
156 "XdndActionMove",
157 "XdndActionLink",
158 "XdndActionAsk",
159 "XdndActionPrivate",
160 "XdndSelection",
161 "XdndTarget",
162 "XdndTypeList",
163 "WCF_DIB",
164 "image/gif",
165 "text/html",
166 "text/plain",
167 "text/rtf",
168 "text/richtext",
169 "text/uri-list"
172 /***********************************************************************
173 * ignore_error
175 * Check if the X error is one we can ignore.
177 static inline BOOL ignore_error( Display *display, XErrorEvent *event )
179 if (event->request_code == X_SetInputFocus && event->error_code == BadMatch) return TRUE;
181 /* ignore a number of errors on gdi display caused by creating/destroying windows */
182 if (display == gdi_display)
184 if (event->error_code == BadDrawable || event->error_code == BadGC) return TRUE;
185 #ifdef HAVE_X11_EXTENSIONS_XRENDER_H
186 if (xrender_error_base) /* check for XRender errors */
188 if (event->error_code == xrender_error_base + BadPicture) return TRUE;
190 #endif
192 return FALSE;
196 /***********************************************************************
197 * X11DRV_expect_error
199 * Setup a callback function that will be called on an X error. The
200 * callback must return non-zero if the error is the one it expected.
201 * This function acquires the x11 lock; X11DRV_check_error must be
202 * called in all cases to release it.
204 void X11DRV_expect_error( Display *display, x11drv_error_callback callback, void *arg )
206 wine_tsx11_lock();
207 err_callback = callback;
208 err_callback_display = display;
209 err_callback_arg = arg;
210 err_callback_result = 0;
211 err_serial = NextRequest(display);
215 /***********************************************************************
216 * X11DRV_check_error
218 * Check if an expected X11 error occurred; return non-zero if yes.
219 * Also release the x11 lock obtained in X11DRV_expect_error.
220 * The caller is responsible for calling XSync first if necessary.
222 int X11DRV_check_error(void)
224 int ret;
225 err_callback = NULL;
226 ret = err_callback_result;
227 wine_tsx11_unlock();
228 return ret;
232 /***********************************************************************
233 * error_handler
235 static int error_handler( Display *display, XErrorEvent *error_evt )
237 if (err_callback && display == err_callback_display &&
238 (long)(error_evt->serial - err_serial) >= 0)
240 if ((err_callback_result = err_callback( display, error_evt, err_callback_arg )))
242 TRACE( "got expected error %d req %d\n",
243 error_evt->error_code, error_evt->request_code );
244 return 0;
247 if (ignore_error( display, error_evt ))
249 TRACE( "got ignored error %d req %d\n",
250 error_evt->error_code, error_evt->request_code );
251 return 0;
253 if (TRACE_ON(synchronous))
255 ERR( "X protocol error: serial=%ld, request_code=%d - breaking into debugger\n",
256 error_evt->serial, error_evt->request_code );
257 DebugBreak(); /* force an entry in the debugger */
259 old_error_handler( display, error_evt );
260 return 0;
263 /***********************************************************************
264 * wine_tsx11_lock (X11DRV.@)
266 void wine_tsx11_lock(void)
268 EnterCriticalSection( &X11DRV_CritSection );
271 /***********************************************************************
272 * wine_tsx11_unlock (X11DRV.@)
274 void wine_tsx11_unlock(void)
276 LeaveCriticalSection( &X11DRV_CritSection );
280 /***********************************************************************
281 * depth_to_bpp
283 * Convert X11-reported depth to the BPP value that Windows apps expect to see.
285 unsigned int depth_to_bpp( unsigned int depth )
287 switch (depth)
289 case 1:
290 case 8:
291 return depth;
292 case 15:
293 case 16:
294 return 16;
295 case 24:
296 /* This is not necessarily right. X11 always has 24 bits per pixel, but it can run
297 * with 24 bit framebuffers and 32 bit framebuffers. It doesn't make any difference
298 * for windowing, but gl applications can get visuals with alpha channels. So we
299 * should check the framebuffer and/or opengl formats available to find out what the
300 * framebuffer actually does
302 case 32:
303 return 32;
304 default:
305 FIXME( "Unexpected X11 depth %d bpp, what to report to app?\n", depth );
306 return depth;
311 /***********************************************************************
312 * get_config_key
314 * Get a config key from either the app-specific or the default config
316 static inline DWORD get_config_key( HKEY defkey, HKEY appkey, const char *name,
317 char *buffer, DWORD size )
319 if (appkey && !RegQueryValueExA( appkey, name, 0, NULL, (LPBYTE)buffer, &size )) return 0;
320 if (defkey && !RegQueryValueExA( defkey, name, 0, NULL, (LPBYTE)buffer, &size )) return 0;
321 return ERROR_FILE_NOT_FOUND;
325 /***********************************************************************
326 * setup_options
328 * Setup the x11drv options.
330 static void setup_options(void)
332 char buffer[MAX_PATH+16];
333 HKEY hkey, appkey = 0;
334 DWORD len;
336 /* @@ Wine registry key: HKCU\Software\Wine\X11 Driver */
337 if (RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\X11 Driver", &hkey )) hkey = 0;
339 /* open the app-specific key */
341 len = (GetModuleFileNameA( 0, buffer, MAX_PATH ));
342 if (len && len < MAX_PATH)
344 HKEY tmpkey;
345 char *p, *appname = buffer;
346 if ((p = strrchr( appname, '/' ))) appname = p + 1;
347 if ((p = strrchr( appname, '\\' ))) appname = p + 1;
348 strcat( appname, "\\X11 Driver" );
349 /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\X11 Driver */
350 if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\AppDefaults", &tmpkey ))
352 if (RegOpenKeyA( tmpkey, appname, &appkey )) appkey = 0;
353 RegCloseKey( tmpkey );
357 if (!get_config_key( hkey, appkey, "Managed", buffer, sizeof(buffer) ))
358 managed_mode = IS_OPTION_TRUE( buffer[0] );
360 if (!get_config_key( hkey, appkey, "DXGrab", buffer, sizeof(buffer) ))
361 dxgrab = IS_OPTION_TRUE( buffer[0] );
363 if (!get_config_key( hkey, appkey, "UseXVidMode", buffer, sizeof(buffer) ))
364 usexvidmode = IS_OPTION_TRUE( buffer[0] );
366 if (!get_config_key( hkey, appkey, "UseXRandR", buffer, sizeof(buffer) ))
367 usexrandr = IS_OPTION_TRUE( buffer[0] );
369 if (!get_config_key( hkey, appkey, "UseTakeFocus", buffer, sizeof(buffer) ))
370 use_take_focus = IS_OPTION_TRUE( buffer[0] );
372 if (!get_config_key( hkey, appkey, "UsePrimarySelection", buffer, sizeof(buffer) ))
373 use_primary_selection = IS_OPTION_TRUE( buffer[0] );
375 screen_depth = 0;
376 if (!get_config_key( hkey, appkey, "ScreenDepth", buffer, sizeof(buffer) ))
377 screen_depth = atoi(buffer);
379 if (!get_config_key( hkey, appkey, "ClientSideWithCore", buffer, sizeof(buffer) ))
380 client_side_with_core = IS_OPTION_TRUE( buffer[0] );
382 if (!get_config_key( hkey, appkey, "ClientSideWithRender", buffer, sizeof(buffer) ))
383 client_side_with_render = IS_OPTION_TRUE( buffer[0] );
385 if (!get_config_key( hkey, appkey, "ClientSideAntiAliasWithCore", buffer, sizeof(buffer) ))
386 client_side_antialias_with_core = IS_OPTION_TRUE( buffer[0] );
388 if (!get_config_key( hkey, appkey, "ClientSideAntiAliasWithRender", buffer, sizeof(buffer) ))
389 client_side_antialias_with_render = IS_OPTION_TRUE( buffer[0] );
391 if (!get_config_key( hkey, appkey, "UseXIM", buffer, sizeof(buffer) ))
392 use_xim = IS_OPTION_TRUE( buffer[0] );
394 if (!get_config_key( hkey, appkey, "PrivateColorMap", buffer, sizeof(buffer) ))
395 private_color_map = IS_OPTION_TRUE( buffer[0] );
397 if (!get_config_key( hkey, appkey, "PrimaryMonitor", buffer, sizeof(buffer) ))
398 primary_monitor = atoi( buffer );
400 if (!get_config_key( hkey, appkey, "CopyDefaultColors", buffer, sizeof(buffer) ))
401 copy_default_colors = atoi(buffer);
403 if (!get_config_key( hkey, appkey, "AllocSystemColors", buffer, sizeof(buffer) ))
404 alloc_system_colors = atoi(buffer);
406 get_config_key( hkey, appkey, "InputStyle", input_style, sizeof(input_style) );
408 if (appkey) RegCloseKey( appkey );
409 if (hkey) RegCloseKey( hkey );
412 #ifdef SONAME_LIBXCOMPOSITE
414 #define MAKE_FUNCPTR(f) typeof(f) * p##f;
415 MAKE_FUNCPTR(XCompositeQueryExtension)
416 MAKE_FUNCPTR(XCompositeQueryVersion)
417 MAKE_FUNCPTR(XCompositeVersion)
418 MAKE_FUNCPTR(XCompositeRedirectWindow)
419 MAKE_FUNCPTR(XCompositeRedirectSubwindows)
420 MAKE_FUNCPTR(XCompositeUnredirectWindow)
421 MAKE_FUNCPTR(XCompositeUnredirectSubwindows)
422 MAKE_FUNCPTR(XCompositeCreateRegionFromBorderClip)
423 MAKE_FUNCPTR(XCompositeNameWindowPixmap)
424 #undef MAKE_FUNCPTR
426 static int xcomp_event_base;
427 static int xcomp_error_base;
429 static void X11DRV_XComposite_Init(void)
431 void *xcomposite_handle = wine_dlopen(SONAME_LIBXCOMPOSITE, RTLD_NOW, NULL, 0);
432 if (!xcomposite_handle)
434 TRACE("Unable to open %s, XComposite disabled\n", SONAME_LIBXCOMPOSITE);
435 usexcomposite = 0;
436 return;
439 #define LOAD_FUNCPTR(f) \
440 if((p##f = wine_dlsym(xcomposite_handle, #f, NULL, 0)) == NULL) \
441 goto sym_not_found;
442 LOAD_FUNCPTR(XCompositeQueryExtension)
443 LOAD_FUNCPTR(XCompositeQueryVersion)
444 LOAD_FUNCPTR(XCompositeVersion)
445 LOAD_FUNCPTR(XCompositeRedirectWindow)
446 LOAD_FUNCPTR(XCompositeRedirectSubwindows)
447 LOAD_FUNCPTR(XCompositeUnredirectWindow)
448 LOAD_FUNCPTR(XCompositeUnredirectSubwindows)
449 LOAD_FUNCPTR(XCompositeCreateRegionFromBorderClip)
450 LOAD_FUNCPTR(XCompositeNameWindowPixmap)
451 #undef LOAD_FUNCPTR
453 if(!pXCompositeQueryExtension(gdi_display, &xcomp_event_base,
454 &xcomp_error_base)) {
455 TRACE("XComposite extension could not be queried; disabled\n");
456 wine_dlclose(xcomposite_handle, NULL, 0);
457 xcomposite_handle = NULL;
458 usexcomposite = 0;
459 return;
461 TRACE("XComposite is up and running error_base = %d\n", xcomp_error_base);
462 return;
464 sym_not_found:
465 TRACE("Unable to load function pointers from %s, XComposite disabled\n", SONAME_LIBXCOMPOSITE);
466 wine_dlclose(xcomposite_handle, NULL, 0);
467 xcomposite_handle = NULL;
468 usexcomposite = 0;
470 #endif /* defined(SONAME_LIBXCOMPOSITE) */
473 /***********************************************************************
474 * X11DRV process initialisation routine
476 static BOOL process_attach(void)
478 Display *display;
479 XVisualInfo *desktop_vi = NULL;
480 const char *env;
482 setup_options();
484 if ((thread_data_tls_index = TlsAlloc()) == TLS_OUT_OF_INDEXES) return FALSE;
486 /* Open display */
488 if (!(env = getenv("XMODIFIERS")) || !*env) /* try to avoid the Xlib XIM locking bug */
489 if (!XInitThreads()) ERR( "XInitThreads failed, trouble ahead\n" );
491 if (!(display = XOpenDisplay( NULL ))) return FALSE;
493 fcntl( ConnectionNumber(display), F_SETFD, 1 ); /* set close on exec flag */
494 screen = DefaultScreenOfDisplay( display );
495 visual = DefaultVisual( display, DefaultScreen(display) );
496 root_window = DefaultRootWindow( display );
497 gdi_display = display;
498 old_error_handler = XSetErrorHandler( error_handler );
500 /* Initialize screen depth */
502 if (screen_depth) /* depth specified */
504 int depth_count, i;
505 int *depth_list = XListDepths(display, DefaultScreen(display), &depth_count);
506 for (i = 0; i < depth_count; i++)
507 if (depth_list[i] == screen_depth) break;
508 XFree( depth_list );
509 if (i >= depth_count)
511 WARN( "invalid depth %d, using default\n", screen_depth );
512 screen_depth = 0;
515 if (!screen_depth) screen_depth = DefaultDepthOfScreen( screen );
517 /* If OpenGL is available, change the default visual, etc as necessary */
518 if ((desktop_vi = X11DRV_setup_opengl_visual( display )))
520 visual = desktop_vi->visual;
521 screen = ScreenOfDisplay(display, desktop_vi->screen);
522 screen_depth = desktop_vi->depth;
523 XFree(desktop_vi);
525 screen_bpp = depth_to_bpp( screen_depth );
527 XInternAtoms( display, (char **)atom_names, NB_XATOMS - FIRST_XATOM, False, X11DRV_Atoms );
529 if (TRACE_ON(synchronous)) XSynchronize( display, True );
531 xinerama_init( WidthOfScreen(screen), HeightOfScreen(screen) );
532 X11DRV_Settings_Init();
534 #ifdef HAVE_LIBXXF86VM
535 /* initialize XVidMode */
536 X11DRV_XF86VM_Init();
537 #endif
538 #ifdef SONAME_LIBXRANDR
539 /* initialize XRandR */
540 X11DRV_XRandR_Init();
541 #endif
542 #ifdef SONAME_LIBXCOMPOSITE
543 X11DRV_XComposite_Init();
544 #endif
546 X11DRV_InitKeyboard();
547 X11DRV_InitClipboard();
549 return TRUE;
553 /***********************************************************************
554 * X11DRV thread termination routine
556 static void thread_detach(void)
558 struct x11drv_thread_data *data = TlsGetValue( thread_data_tls_index );
560 if (data)
562 X11DRV_ResetSelectionOwner();
563 wine_tsx11_lock();
564 if (data->xim) XCloseIM( data->xim );
565 XCloseDisplay( data->display );
566 wine_tsx11_unlock();
567 HeapFree( GetProcessHeap(), 0, data );
572 /***********************************************************************
573 * X11DRV process termination routine
575 static void process_detach(void)
577 #ifdef HAVE_LIBXXF86VM
578 /* cleanup XVidMode */
579 X11DRV_XF86VM_Cleanup();
580 #endif
581 if(using_client_side_fonts)
582 X11DRV_XRender_Finalize();
584 /* cleanup GDI */
585 X11DRV_GDI_Finalize();
587 DeleteCriticalSection( &X11DRV_CritSection );
588 TlsFree( thread_data_tls_index );
592 /* store the display fd into the message queue */
593 static void set_queue_display_fd( Display *display )
595 HANDLE handle;
596 int ret;
598 if (wine_server_fd_to_handle( ConnectionNumber(display), GENERIC_READ | SYNCHRONIZE, 0, &handle ))
600 MESSAGE( "x11drv: Can't allocate handle for display fd\n" );
601 ExitProcess(1);
603 SERVER_START_REQ( set_queue_fd )
605 req->handle = handle;
606 ret = wine_server_call( req );
608 SERVER_END_REQ;
609 if (ret)
611 MESSAGE( "x11drv: Can't store handle for display fd\n" );
612 ExitProcess(1);
614 CloseHandle( handle );
618 /***********************************************************************
619 * X11DRV thread initialisation routine
621 struct x11drv_thread_data *x11drv_init_thread_data(void)
623 struct x11drv_thread_data *data;
625 if (!(data = HeapAlloc( GetProcessHeap(), 0, sizeof(*data) )))
627 ERR( "could not create data\n" );
628 ExitProcess(1);
630 wine_tsx11_lock();
631 if (!(data->display = XOpenDisplay(NULL)))
633 wine_tsx11_unlock();
634 MESSAGE( "x11drv: Can't open display: %s\n", XDisplayName(NULL) );
635 MESSAGE( "Please ensure that your X server is running and that $DISPLAY is set correctly.\n" );
636 ExitProcess(1);
639 fcntl( ConnectionNumber(data->display), F_SETFD, 1 ); /* set close on exec flag */
641 #ifdef HAVE_XKB
642 if (use_xkb)
644 use_xkb = XkbUseExtension( data->display, NULL, NULL );
645 if (use_xkb)
647 /* Hack: dummy call to XkbKeysymToModifiers to force initialisation of Xkb internals */
648 /* This works around an Xlib bug where it tries to get the display lock */
649 /* twice during XFilterEvents if Xkb hasn't been initialised yet. */
650 XkbKeysymToModifiers( data->display, 'A' );
651 XkbSetDetectableAutoRepeat( data->display, True, NULL );
654 #endif
656 if (TRACE_ON(synchronous)) XSynchronize( data->display, True );
657 wine_tsx11_unlock();
659 if (!use_xim)
660 data->xim = NULL;
661 else if (!(data->xim = X11DRV_SetupXIM( data->display, input_style )))
662 WARN("Input Method is not available\n");
664 set_queue_display_fd( data->display );
665 data->process_event_count = 0;
666 data->cursor = None;
667 data->cursor_window = None;
668 data->grab_window = None;
669 data->last_focus = 0;
670 data->selection_wnd = 0;
671 TlsSetValue( thread_data_tls_index, data );
672 return data;
676 /***********************************************************************
677 * X11DRV initialisation routine
679 BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
681 BOOL ret = TRUE;
683 switch(reason)
685 case DLL_PROCESS_ATTACH:
686 ret = process_attach();
687 break;
688 case DLL_THREAD_DETACH:
689 thread_detach();
690 break;
691 case DLL_PROCESS_DETACH:
692 process_detach();
693 break;
695 return ret;
698 /***********************************************************************
699 * GetScreenSaveActive (X11DRV.@)
701 * Returns the active status of the screen saver
703 BOOL X11DRV_GetScreenSaveActive(void)
705 int timeout, temp;
706 wine_tsx11_lock();
707 XGetScreenSaver(gdi_display, &timeout, &temp, &temp, &temp);
708 wine_tsx11_unlock();
709 return timeout != 0;
712 /***********************************************************************
713 * SetScreenSaveActive (X11DRV.@)
715 * Activate/Deactivate the screen saver
717 void X11DRV_SetScreenSaveActive(BOOL bActivate)
719 int timeout, interval, prefer_blanking, allow_exposures;
720 static int last_timeout = 15 * 60;
722 wine_tsx11_lock();
723 XGetScreenSaver(gdi_display, &timeout, &interval, &prefer_blanking,
724 &allow_exposures);
725 if (timeout) last_timeout = timeout;
727 timeout = bActivate ? last_timeout : 0;
728 XSetScreenSaver(gdi_display, timeout, interval, prefer_blanking,
729 allow_exposures);
730 wine_tsx11_unlock();