Removed a few dependencies on kernel32 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
8 #include "config.h"
9
10 #include <fcntl.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <sys/time.h>
14 #include <unistd.h>
15 #include <X11/cursorfont.h>
16 #include "ts_xlib.h"
17 #include "ts_xutil.h"
18 #include "ts_shape.h"
19
20 #include "winbase.h"
21 #include "wine/winbase16.h"
22 #include "winreg.h"
23
24 #include "callback.h"
25 #include "debugtools.h"
26 #include "gdi.h"
27 #include "options.h"
28 #include "user.h"
29 #include "win.h"
30 #include "wine_gl.h"
31 #include "x11drv.h"
32
33 DEFAULT_DEBUG_CHANNEL(x11drv);
34
35 static XKeyboardState keyboard_state;
36
37 Display *display;
38 Screen *screen;
39 Visual *visual;
40 unsigned int screen_width;
41 unsigned int screen_height;
42 unsigned int screen_depth;
43 Window root_window;
44
45 unsigned int X11DRV_server_startticks;
46
47 /***********************************************************************
48  *              error_handler
49  */
50 static int error_handler(Display *display, XErrorEvent *error_evt)
51 {
52     DebugBreak();  /* force an entry in the debugger */
53     return 0;
54 }
55
56
57 /***********************************************************************
58  *              get_server_startup
59  *
60  * Get the server startup time 
61  * Won't be exact, but should be sufficient
62  */
63 static void get_server_startup(void)
64 {
65     struct timeval t;
66     gettimeofday( &t, NULL );
67     X11DRV_server_startticks = ((t.tv_sec * 1000) + (t.tv_usec / 1000)) - GetTickCount();
68 }
69
70
71 /***********************************************************************
72  *              setup_options
73  *
74  * Setup the x11drv options.
75  */
76 static void setup_options(void)
77 {
78     char buffer[256];
79     HKEY hkey;
80     DWORD type, count;
81
82     if (RegCreateKeyExA( HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\x11drv", 0, NULL,
83                          REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL ))
84     {
85         ERR("Cannot create config registry key\n" );
86         ExitProcess(1);
87     }
88
89     /* --display option */
90
91     count = sizeof(buffer);
92     if (!RegQueryValueExA( hkey, "display", 0, &type, buffer, &count ))
93     {
94         if (Options.display)
95         {
96             if (strcmp( buffer, Options.display ))
97                 MESSAGE( "%s: warning: --display option ignored, using '%s'\n", argv0, buffer );
98         }
99         else if ((Options.display = getenv( "DISPLAY" )))
100         {
101             if (strcmp( buffer, Options.display ))
102                 MESSAGE( "%s: warning: $DISPLAY variable ignored, using '%s'\n", argv0, buffer );
103         }
104         Options.display = strdup(buffer);
105     }
106     else
107     {
108         if (!Options.display && !(Options.display = getenv( "DISPLAY" )))
109         {
110             MESSAGE( "%s: no display specified\n", argv0 );
111             ExitProcess(1);
112         }
113         RegSetValueExA( hkey, "display", 0, REG_SZ, Options.display, strlen(Options.display)+1 );
114     }
115
116     /* --managed option */
117
118     if (!Options.managed)
119     {
120         count = sizeof(buffer);
121         if (!RegQueryValueExA( hkey, "managed", 0, &type, buffer, &count ))
122             Options.managed = IS_OPTION_TRUE( buffer[0] );
123     }
124     else RegSetValueExA( hkey, "managed", 0, REG_SZ, "y", 2 );
125
126     RegCloseKey( hkey );
127 }
128
129    
130 /***********************************************************************
131  *              create_desktop
132  *
133  * Create the desktop window for the --desktop mode.
134  */
135 static void create_desktop( const char *geometry )
136 {
137     int x = 0, y = 0, flags;
138     unsigned int width = 640, height = 480;  /* Default size = 640x480 */
139     char *name = "Wine desktop";
140     XSizeHints *size_hints;
141     XWMHints   *wm_hints;
142     XClassHint *class_hints;
143     XSetWindowAttributes win_attr;
144     XTextProperty window_name;
145     Atom XA_WM_DELETE_WINDOW;
146     /* Used to create the desktop window with a good visual */
147     XVisualInfo *vi = NULL;
148 #ifdef HAVE_OPENGL
149     BOOL dblbuf_visual;
150
151     /* Get in wine.ini if the desktop window should have a double-buffered visual or not */
152     dblbuf_visual = PROFILE_GetWineIniBool( "x11drv", "DesktopDoubleBuffered", 0 );
153     if (dblbuf_visual)  {
154       int dblBuf[]={GLX_RGBA,GLX_DEPTH_SIZE,16,GLX_DOUBLEBUFFER,None};
155       
156       ENTER_GL();
157       vi = glXChooseVisual(display, DefaultScreen(display), dblBuf);
158       win_attr.colormap = XCreateColormap(display, RootWindow(display,vi->screen),
159                                          vi->visual, AllocNone);
160       LEAVE_GL();
161     }
162 #endif /* HAVE_OPENGL */    
163
164     flags = TSXParseGeometry( geometry, &x, &y, &width, &height );
165     screen_width  = width;
166     screen_height = height;
167
168     /* Create window */
169     win_attr.background_pixel = BlackPixel(display, 0);
170     win_attr.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask |
171                           PointerMotionMask | ButtonPressMask |
172                           ButtonReleaseMask | EnterWindowMask;
173     win_attr.cursor = TSXCreateFontCursor( display, XC_top_left_arrow );
174
175     if (vi != NULL) {
176       visual       = vi->visual;
177       screen       = ScreenOfDisplay(display, vi->screen);
178       screen_depth = vi->depth;
179     }
180     root_window = TSXCreateWindow( display,
181                                    (vi == NULL ? DefaultRootWindow(display) : RootWindow(display, vi->screen)),
182                                    x, y, width, height, 0,
183                                    (vi == NULL ? CopyFromParent : vi->depth),
184                                    InputOutput,
185                                    (vi == NULL ? CopyFromParent : vi->visual),
186                                    CWBackPixel | CWEventMask | CWCursor | (vi == NULL ? 0 : CWColormap),
187                                    &win_attr );
188   
189     /* Set window manager properties */
190     size_hints  = TSXAllocSizeHints();
191     wm_hints    = TSXAllocWMHints();
192     class_hints = TSXAllocClassHint();
193     if (!size_hints || !wm_hints || !class_hints)
194     {
195         MESSAGE("Not enough memory for window manager hints.\n" );
196         ExitProcess(1);
197     }
198     size_hints->min_width = size_hints->max_width = width;
199     size_hints->min_height = size_hints->max_height = height;
200     size_hints->flags = PMinSize | PMaxSize;
201     if (flags & (XValue | YValue)) size_hints->flags |= USPosition;
202     if (flags & (WidthValue | HeightValue)) size_hints->flags |= USSize;
203     else size_hints->flags |= PSize;
204
205     wm_hints->flags = InputHint | StateHint;
206     wm_hints->input = True;
207     wm_hints->initial_state = NormalState;
208     class_hints->res_name = (char *)argv0;
209     class_hints->res_class = "Wine";
210
211     TSXStringListToTextProperty( &name, 1, &window_name );
212     TSXSetWMProperties( display, root_window, &window_name, &window_name,
213                         NULL, 0, size_hints, wm_hints, class_hints );
214     XA_WM_DELETE_WINDOW = TSXInternAtom( display, "WM_DELETE_WINDOW", False );
215     TSXSetWMProtocols( display, root_window, &XA_WM_DELETE_WINDOW, 1 );
216     TSXFree( size_hints );
217     TSXFree( wm_hints );
218     TSXFree( class_hints );
219
220     /* Map window */
221     TSXMapWindow( display, root_window );
222 }
223
224 /* Created so that XOpenIM can be called using the 'large stack' */
225 static void XOpenIM_large_stack(void)
226 {
227   TSXOpenIM(display,NULL,NULL,NULL);
228 }
229
230 /***********************************************************************
231  *           X11DRV process initialisation routine
232  */
233 static void process_attach(void)
234 {
235     WND_Driver       = &X11DRV_WND_Driver;
236
237     get_server_startup();
238     setup_options();
239
240     /* Open display */
241
242     if (!(display = TSXOpenDisplay( Options.display )))
243     {
244         MESSAGE( "%s: Can't open display: %s\n", argv0, Options.display );
245         ExitProcess(1);
246     }
247     fcntl( ConnectionNumber(display), F_SETFD, 1 ); /* set close on exec flag */
248     screen = DefaultScreenOfDisplay( display );
249     visual = DefaultVisual( display, DefaultScreen(display) );
250     root_window = DefaultRootWindow( display );
251
252     /* Initialize screen depth */
253
254     screen_depth = PROFILE_GetWineIniInt( "x11drv", "ScreenDepth", 0 );
255     if (screen_depth)  /* depth specified */
256     {
257         int depth_count, i;
258         int *depth_list = TSXListDepths(display, DefaultScreen(display), &depth_count);
259         for (i = 0; i < depth_count; i++)
260             if (depth_list[i] == screen_depth) break;
261         TSXFree( depth_list );
262         if (i >= depth_count)
263         {
264             MESSAGE( "%s: Depth %d not supported on this screen.\n", argv0, screen_depth );
265             ExitProcess(1);
266         }
267     }
268     else screen_depth = DefaultDepthOfScreen( screen );
269
270     /* tell the libX11 that we will do input method handling ourselves
271      * that keep libX11 from doing anything whith dead keys, allowing Wine
272      * to have total control over dead keys, that is this line allows
273      * them to work in Wine, even whith a libX11 including the dead key
274      * patches from Th.Quinot (http://Web.FdN.FR/~tquinot/dead-keys.en.html)
275      */
276     CALL_LARGE_STACK( XOpenIM_large_stack, NULL );
277
278     if (Options.synchronous) XSetErrorHandler( error_handler );
279
280     screen_width  = WidthOfScreen( screen );
281     screen_height = HeightOfScreen( screen );
282
283     if (Options.desktopGeometry)
284     {
285         Options.managed = FALSE;
286         create_desktop( Options.desktopGeometry );
287     }
288
289     /* initialize GDI */
290     X11DRV_GDI_Initialize();
291
292     /* save keyboard setup */
293     TSXGetKeyboardControl(display, &keyboard_state);
294
295     /* initialize event handling */
296     X11DRV_EVENT_Init();
297
298     /* load display.dll */
299     LoadLibrary16( "display" );
300 }
301
302
303 /***********************************************************************
304  *           X11DRV process termination routine
305  */
306 static void process_detach(void)
307 {
308     /* restore keyboard setup */
309     XKeyboardControl keyboard_value;
310   
311     keyboard_value.key_click_percent = keyboard_state.key_click_percent;
312     keyboard_value.bell_percent      = keyboard_state.bell_percent;
313     keyboard_value.bell_pitch        = keyboard_state.bell_pitch;
314     keyboard_value.bell_duration     = keyboard_state.bell_duration;
315     keyboard_value.auto_repeat_mode  = keyboard_state.global_auto_repeat;
316   
317     XChangeKeyboardControl(display, KBKeyClickPercent | KBBellPercent | 
318                            KBBellPitch | KBBellDuration | KBAutoRepeatMode, &keyboard_value);
319
320     /* cleanup GDI */
321     X11DRV_GDI_Finalize();
322
323 #if 0  /* FIXME */
324
325     /* close the display */
326     XCloseDisplay( display );
327     display = NULL;
328
329     WND_Driver       = NULL;
330 #endif
331 }
332
333
334 /***********************************************************************
335  *           X11DRV initialisation routine
336  */
337 BOOL WINAPI X11DRV_Init( HINSTANCE hinst, DWORD reason, LPVOID reserved )
338 {
339     static int process_count;
340
341     switch(reason)
342     {
343     case DLL_PROCESS_ATTACH:
344         if (!process_count++) process_attach();
345         break;
346     case DLL_PROCESS_DETACH:
347         if (!--process_count) process_detach();
348         break;
349     }
350     return TRUE;
351 }
352
353 /***********************************************************************
354  *              X11DRV_GetScreenSaveActive
355  *
356  * Returns the active status of the screen saver
357  */
358 BOOL X11DRV_GetScreenSaveActive(void)
359 {
360     int timeout, temp;
361     TSXGetScreenSaver(display, &timeout, &temp, &temp, &temp);
362     return timeout != 0;
363 }
364
365 /***********************************************************************
366  *              X11DRV_SetScreenSaveActive
367  *
368  * Activate/Deactivate the screen saver
369  */
370 void X11DRV_SetScreenSaveActive(BOOL bActivate)
371 {
372     if(bActivate)
373         TSXActivateScreenSaver(display);
374     else
375         TSXResetScreenSaver(display);
376 }
377
378 /***********************************************************************
379  *              X11DRV_GetScreenSaveTimeout
380  *
381  * Return the screen saver timeout
382  */
383 int X11DRV_GetScreenSaveTimeout(void)
384 {
385     int timeout, temp;
386     TSXGetScreenSaver(display, &timeout, &temp, &temp, &temp);
387     return timeout;
388 }
389
390 /***********************************************************************
391  *              X11DRV_SetScreenSaveTimeout
392  *
393  * Set the screen saver timeout
394  */
395 void X11DRV_SetScreenSaveTimeout(int nTimeout)
396 {
397     /* timeout is a 16bit entity (CARD16) in the protocol, so it should
398      * not get over 32767 or it will get negative. */
399     if (nTimeout>32767) nTimeout = 32767;
400     TSXSetScreenSaver(display, nTimeout, 60, DefaultBlanking, DefaultExposures);
401 }
402
403 /***********************************************************************
404  *              X11DRV_IsSingleWindow
405  */
406 BOOL X11DRV_IsSingleWindow(void)
407 {
408     return (root_window != DefaultRootWindow(display));
409 }