Release 970215
[wine] / misc / main.c
1 /*
2  * Main function.
3  *
4  * Copyright 1994 Alexandre Julliard
5  */
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <unistd.h>
11 #include <ctype.h>
12 /* #include <locale.h> */
13 #ifdef MALLOC_DEBUGGING
14 #include <malloc.h>
15 #endif
16 #include <X11/Xlib.h>
17 #include <X11/Xresource.h>
18 #include <X11/Xutil.h>
19 #include <X11/Xlocale.h>
20 #include <X11/cursorfont.h>
21 #include "heap.h"
22 #include "message.h"
23 #include "module.h"
24 #include "msdos.h"
25 #include "windows.h"
26 #include "color.h"
27 #include "winsock.h"
28 #include "options.h"
29 #include "desktop.h"
30 #include "shell.h"
31 #include "winbase.h"
32 #define DEBUG_DEFINE_VARIABLES
33 #include "stddebug.h"
34 #include "debug.h"
35 #include "xmalloc.h"
36
37 const char people[] = "Wine is available thanks to the work of "
38 "Bob Amstadt, Dag Asheim, Martin Ayotte, Ross Biro, Uwe Bonnes, Erik Bos, "
39 "Fons Botman, John Brezak, Andrew Bulhak, John Burton, "
40 "Niels de Carpentier, Roman Dolejsi, Frans van Dorsselaer, Paul Falstad, "
41 "Olaf Flebbe, Peter Galbavy, Ramon Garcia, Hans de Graaff, "
42 "Charles M. Hannum, John Harvey, Cameron Heide, Jochen Hoenicke, "
43 "Onno Hovers, Jeffrey Hsu, Miguel de Icaza, Jukka Iivonen, "
44 "Alexandre Julliard, Jochen Karrer, Andreas Kirschbaum, Albrecht Kleine, "
45 "Jon Konrath, Alex Korobka, Greg Kreider, Anand Kumria, Scott A. Laird, "
46 "Martin von Loewis, Kenneth MacDonald, Peter MacDonald, William Magro, "
47 "Juergen Marquardt, Marcus Meissner, Graham Menhennitt, David Metcalfe, "
48 "Steffen Moeller, Philippe De Muyter, Itai Nahshon, Michael Patra, "
49 "Jim Peterson, Robert Pouliot, Keith Reynolds, John Richardson, "
50 "Johannes Ruscheinski, Thomas Sandford, Constantine Sapuntzakis, "
51 "Daniel Schepler, Ulrich Schmid, Bernd Schmidt, Yngvi Sigurjonsson, "
52 "Rick Sladkey, William Smith, Erik Svendsen, Tristan Tarrant, "
53 "Andrew Taylor, Duncan C Thomson, Goran Thyni, Jimmy Tirtawangsa, "
54 "Jon Tombs, Linus Torvalds, Gregory Trubetskoy, Michael Veksler, "
55 "Sven Verdoolaege, Eric Warnke, Manfred Weichel, Morten Welinder, "
56 "Jan Willamowius, Carl Williams, Karl Guenter Wuensch, Eric Youngdale, "
57 "and James Youngman. ";
58
59 const WINE_LANGUAGE_DEF Languages[] =
60 {
61     {"En",0x0409},      /* LANG_En */
62     {"Es",0x040A},      /* LANG_Es */
63     {"De",0x0407},      /* LANG_De */
64     {"No",0x0414},      /* LANG_No */
65     {"Fr",0x0400},      /* LANG_Fr */
66     {"Fi",0x040B},      /* LANG_Fi */
67     {"Da",0x0406},      /* LANG_Da */
68     {"Cz",0x0405},      /* LANG_Cz */
69     {"Eo",     0},      /* LANG_Eo */ /* FIXME languageid */
70     {"It",0x0410},      /* LANG_It */
71     {"Ko",0x0412},      /* LANG_Ko */
72     {"Hu",0x0436},      /* LANG_Hu */
73     {NULL,0}
74 };
75
76 WORD WINE_LanguageId = 0;
77
78 #define WINE_CLASS    "Wine"    /* Class name for resources */
79
80 #define WINE_APP_DEFAULTS "/usr/lib/X11/app-defaults/Wine"
81
82 typedef struct tagENVENTRY {
83   LPSTR                 Name;
84   LPSTR                 Value;
85   WORD                  wSize;
86   struct tagENVENTRY    *Prev;
87   struct tagENVENTRY    *Next;
88 } ENVENTRY, *LPENVENTRY;
89
90 LPENVENTRY      lpEnvList = NULL;
91
92 Display *display;
93 Screen *screen;
94 Window rootWindow;
95 int screenWidth = 0, screenHeight = 0;  /* Desktop window dimensions */
96 int screenDepth = 0;  /* Screen depth to use */
97 int desktopX = 0, desktopY = 0;  /* Desktop window position (if any) */
98 int getVersion16 = 0;
99 int getVersion32 = 0;
100 OSVERSIONINFO32A getVersionEx;
101
102 struct options Options =
103 {  /* default options */
104     NULL,           /* desktopGeometry */
105     NULL,           /* programName */
106     FALSE,          /* usePrivateMap */
107     FALSE,          /* useFixedMap */
108     FALSE,          /* synchronous */
109     FALSE,          /* backing store */
110     SW_SHOWNORMAL,  /* cmdShow */
111     FALSE,
112     FALSE,          /* failReadOnly */
113     MODE_ENHANCED,  /* Enhanced mode */
114     FALSE,          /* IPC enabled */
115 #ifdef DEFAULT_LANG
116     DEFAULT_LANG,   /* Default language */
117 #else
118     LANG_En,
119 #endif
120     FALSE,          /* Managed windows */
121     FALSE           /* Perfect graphics */
122 };
123
124
125 static XrmOptionDescRec optionsTable[] =
126 {
127     { "-backingstore",  ".backingstore",    XrmoptionNoArg,  (caddr_t)"on" },
128     { "-desktop",       ".desktop",         XrmoptionSepArg, (caddr_t)NULL },
129     { "-depth",         ".depth",           XrmoptionSepArg, (caddr_t)NULL },
130     { "-display",       ".display",         XrmoptionSepArg, (caddr_t)NULL },
131     { "-iconic",        ".iconic",          XrmoptionNoArg,  (caddr_t)"on" },
132     { "-ipc",           ".ipc",             XrmoptionNoArg,  (caddr_t)"off"},
133     { "-language",      ".language",        XrmoptionSepArg, (caddr_t)"En" },
134     { "-name",          ".name",            XrmoptionSepArg, (caddr_t)NULL },
135     { "-perfect",       ".perfect",         XrmoptionNoArg,  (caddr_t)"on" },
136     { "-privatemap",    ".privatemap",      XrmoptionNoArg,  (caddr_t)"on" },
137     { "-fixedmap",      ".fixedmap",        XrmoptionNoArg,  (caddr_t)"on" },
138     { "-synchronous",   ".synchronous",     XrmoptionNoArg,  (caddr_t)"on" },
139     { "-debug",         ".debug",           XrmoptionNoArg,  (caddr_t)"on" },
140     { "-debugmsg",      ".debugmsg",        XrmoptionSepArg, (caddr_t)NULL },
141     { "-dll",           ".dll",             XrmoptionSepArg, (caddr_t)NULL },
142     { "-failreadonly",  ".failreadonly",    XrmoptionNoArg,  (caddr_t)"on" },
143     { "-mode",          ".mode",            XrmoptionSepArg, (caddr_t)NULL },
144     { "-managed",       ".managed",         XrmoptionNoArg,  (caddr_t)"off"},
145     { "-winver",        ".winver",          XrmoptionSepArg, (caddr_t)NULL }
146 };
147
148 #define NB_OPTIONS  (sizeof(optionsTable) / sizeof(optionsTable[0]))
149
150 #define USAGE \
151   "Usage:  %s [options] program_name [arguments]\n" \
152   "\n" \
153   "Options:\n" \
154   "    -backingstore   Turn on backing store\n" \
155   "    -debug          Enter debugger before starting application\n" \
156   "    -debugmsg name  Turn debugging-messages on or off\n" \
157   "    -depth n        Change the depth to use for multiple-depth screens\n" \
158   "    -desktop geom   Use a desktop window of the given geometry\n" \
159   "    -display name   Use the specified display\n" \
160   "    -dll name       Enable or disable built-in DLLs\n" \
161   "    -failreadonly   Read only files may not be opened in write mode\n" \
162   "    -fixedmap       Use a \"standard\" color map\n" \
163   "    -iconic         Start as an icon\n" \
164   "    -ipc            Enable IPC facilities\n" \
165   "    -language xx    Set the language (one of En,Es,De,No,Fr,Fi,Da,Cz,Eo,It,Ko,Hu)\n" \
166   "    -managed        Allow the window manager to manage created windows\n" \
167   "    -mode mode      Start Wine in a particular mode (standard or enhanced)\n" \
168   "    -name name      Set the application name\n" \
169   "    -perfect        Favor correctness over speed for graphical operations\n" \
170   "    -privatemap     Use a private color map\n" \
171   "    -synchronous    Turn on synchronous display mode\n" \
172   "    -winver         Version to imitate (one of win31,win95,nt351)\n"
173
174
175
176 /***********************************************************************
177  *           MAIN_Usage
178  */
179 #ifndef WINELIB32
180 void MAIN_Usage( char *name )
181 {
182     fprintf( stderr, USAGE, name );
183     exit(1);
184 }
185 #endif
186
187
188 /***********************************************************************
189  *           MAIN_GetProgramName
190  *
191  * Get the program name. The name is specified by (in order of precedence):
192  * - the option '-name'.
193  * - the environment variable 'WINE_NAME'.
194  * - the last component of argv[0].
195  */
196 static char *MAIN_GetProgramName( int argc, char *argv[] )
197 {
198     int i;
199     char *p;
200
201     for (i = 1; i < argc-1; i++)
202         if (!strcmp( argv[i], "-name" )) return argv[i+1];
203     if ((p = getenv( "WINE_NAME" )) != NULL) return p;
204     if ((p = strrchr( argv[0], '/' )) != NULL) return p+1;
205     return argv[0];
206 }
207
208
209 /***********************************************************************
210  *           MAIN_GetResource
211  *
212  * Fetch the value of resource 'name' using the correct instance name.
213  * 'name' must begin with '.' or '*'
214  */
215 static int MAIN_GetResource( XrmDatabase db, char *name, XrmValue *value )
216 {
217     char *buff_instance, *buff_class;
218     char *dummy;
219     int retval;
220
221     buff_instance = (char *)xmalloc(strlen(Options.programName)+strlen(name)+1);
222     buff_class    = (char *)xmalloc( strlen(WINE_CLASS) + strlen(name) + 1 );
223
224     strcpy( buff_instance, Options.programName );
225     strcat( buff_instance, name );
226     strcpy( buff_class, WINE_CLASS );
227     strcat( buff_class, name );
228     retval = XrmGetResource( db, buff_instance, buff_class, &dummy, value );
229     free( buff_instance );
230     free( buff_class );
231     return retval;
232 }
233
234
235 /***********************************************************************
236  *                    ParseDebugOptions
237  *
238  *  Turns specific debug messages on or off, according to "options".
239  *  Returns TRUE if parsing was successful
240  */
241 #ifdef DEBUG_RUNTIME
242
243 BOOL ParseDebugOptions(char *options)
244 {
245   int l;
246   if (strlen(options)<3)
247     return FALSE;
248   do
249   {
250     if ((*options!='+')&&(*options!='-'))
251       return FALSE;
252     if (strchr(options,','))
253       l=strchr(options,',')-options;
254     else
255       l=strlen(options);
256     if (!lstrncmpi32A(options+1,"all",l-1))
257       {
258         int i;
259         for (i=0;i<sizeof(debug_msg_enabled)/sizeof(short);i++)
260           debug_msg_enabled[i]=(*options=='+');
261       }
262     else
263       {
264         int i;
265         for (i=0;i<sizeof(debug_msg_enabled)/sizeof(short);i++)
266           if (debug_msg_name && (!lstrncmpi32A(options+1,debug_msg_name[i],l-1)))
267             {
268               debug_msg_enabled[i]=(*options=='+');
269               break;
270             }
271         if (i==sizeof(debug_msg_enabled)/sizeof(short))
272           return FALSE;
273       }
274     options+=l;
275   }
276   while((*options==',')&&(*(++options)));
277   if (*options)
278     return FALSE;
279   else
280     return TRUE;
281 }
282
283 #endif
284
285
286 /***********************************************************************
287  *           MAIN_ParseLanguageOption
288  *
289  * Parse -language option.
290  */
291 static void MAIN_ParseLanguageOption( char *arg )
292 {
293     const WINE_LANGUAGE_DEF *p = Languages;
294
295     Options.language = LANG_En;  /* First language */
296     for (;p->name;p++)
297     {
298         if (!lstrcmpi32A( p->name, arg ))
299         {
300             WINE_LanguageId = p->langid;
301             return;
302         }
303         Options.language++;
304     }
305     fprintf( stderr, "Invalid language specified '%s'. Supported languages are: ", arg );
306     for (p = Languages; p->name; p++) fprintf( stderr, "%s ", p->name );
307     fprintf( stderr, "\n" );
308     exit(1);
309 }
310
311
312 /***********************************************************************
313  *           MAIN_ParseModeOption
314  *
315  * Parse -mode option.
316  */
317 static void MAIN_ParseModeOption( char *arg )
318 {
319     if (!lstrcmpi32A("enhanced", arg)) Options.mode = MODE_ENHANCED;
320     else if (!lstrcmpi32A("standard", arg)) Options.mode = MODE_STANDARD;
321     else
322     {
323         fprintf(stderr, "Invalid mode '%s' specified.\n", arg);
324         fprintf(stderr, "Valid modes are: 'standard', 'enhanced' (default).\n");
325         exit(1);
326     }
327 }
328
329 /**********************************************************************
330  *           MAIN_ParseVersion
331  */
332 static void MAIN_ParseVersion( char *arg )
333 {
334     /* If you add any other options, 
335        verify the values you return on the real thing */
336     if(strcmp(arg,"win31")==0) 
337     {
338         getVersion16 = 0x06160A03;
339         /* FIXME: My Win32s installation failed to execute the
340            MSVC 4 test program. So check these values */
341         getVersion32 = 0x80000A03;
342         getVersionEx.dwMajorVersion=3;
343         getVersionEx.dwMinorVersion=10;
344         getVersionEx.dwBuildNumber=0;
345         getVersionEx.dwPlatformId=VER_PLATFORM_WIN32s;
346         strcpy(getVersionEx.szCSDVersion,"Win32s 1.3");
347     }
348     else if(strcmp(arg, "win95")==0)
349     {
350         getVersion16 = 0x07005F03;
351         getVersion32 = 0xC0000004;
352         getVersionEx.dwMajorVersion=4;
353         getVersionEx.dwMinorVersion=0;
354         getVersionEx.dwBuildNumber=0x40003B6;
355         getVersionEx.dwPlatformId=VER_PLATFORM_WIN32_WINDOWS;
356         strcpy(getVersionEx.szCSDVersion,"");
357     }
358     else if(strcmp(arg, "nt351")==0)
359     {
360         getVersion16 = 0x05000A03;
361         getVersion32 = 0x04213303;
362         getVersionEx.dwMajorVersion=3;
363         getVersionEx.dwMinorVersion=51;
364         getVersionEx.dwBuildNumber=0x421;
365         getVersionEx.dwPlatformId=VER_PLATFORM_WIN32_NT;
366         strcpy(getVersionEx.szCSDVersion,"Service Pack 2");
367     }
368     else fprintf(stderr, "Unknown winver system code - ignored\n");
369 }
370
371 /***********************************************************************
372  *           MAIN_ParseOptions
373  *
374  * Parse command line options and open display.
375  */
376 static void MAIN_ParseOptions( int *argc, char *argv[] )
377 {
378     char *display_name = NULL;
379     XrmValue value;
380     XrmDatabase db = XrmGetFileDatabase(WINE_APP_DEFAULTS);
381     int i;
382     char *xrm_string;
383
384     Options.programName = MAIN_GetProgramName( *argc, argv );
385
386       /* Get display name from command line */
387     for (i = 1; i < *argc - 1; i++)
388         if (!strcmp( argv[i], "-display" ))
389         {
390             display_name = argv[i+1];
391             break;
392         }
393
394 #ifdef WINELIB
395     /* Need to assemble command line and pass it to WinMain */
396 #else
397     if (*argc < 2 || lstrcmpi32A(argv[1], "-h") == 0) 
398         MAIN_Usage( argv[0] );
399 #endif
400
401       /* Open display */
402
403     if (display_name == NULL &&
404         MAIN_GetResource( db, ".display", &value )) display_name = value.addr;
405
406     if (!(display = XOpenDisplay( display_name )))
407     {
408         fprintf( stderr, "%s: Can't open display: %s\n",
409                  argv[0], display_name ? display_name : "(none specified)" );
410         exit(1);
411     }
412
413       /* Merge file and screen databases */
414     if ((xrm_string = XResourceManagerString( display )) != NULL)
415     {
416         XrmDatabase display_db = XrmGetStringDatabase( xrm_string );
417         XrmMergeDatabases( display_db, &db );
418     }
419
420       /* Parse command line */
421     XrmParseCommand( &db, optionsTable, NB_OPTIONS,
422                      Options.programName, argc, argv );
423
424       /* Get all options */
425     if (MAIN_GetResource( db, ".iconic", &value ))
426         Options.cmdShow = SW_SHOWMINIMIZED;
427     if (MAIN_GetResource( db, ".privatemap", &value ))
428         Options.usePrivateMap = TRUE;
429     if (MAIN_GetResource( db, ".fixedmap", &value ))
430         Options.useFixedMap = TRUE;
431     if (MAIN_GetResource( db, ".synchronous", &value ))
432         Options.synchronous = TRUE;
433     if (MAIN_GetResource( db, ".backingstore", &value ))
434         Options.backingstore = TRUE;    
435     if (MAIN_GetResource( db, ".debug", &value ))
436         Options.debug = TRUE;
437     if (MAIN_GetResource( db, ".failreadonly", &value ))
438         Options.failReadOnly = TRUE;
439     if (MAIN_GetResource( db, ".ipc", &value ))
440         Options.ipc = TRUE;
441     if (MAIN_GetResource( db, ".perfect", &value ))
442         Options.perfectGraphics = TRUE;
443     if (MAIN_GetResource( db, ".depth", &value))
444         screenDepth = atoi( value.addr );
445     if (MAIN_GetResource( db, ".desktop", &value))
446         Options.desktopGeometry = value.addr;
447     if (MAIN_GetResource( db, ".language", &value))
448         MAIN_ParseLanguageOption( (char *)value.addr );
449     if (MAIN_GetResource( db, ".managed", &value))
450         Options.managed = TRUE;
451     if (MAIN_GetResource( db, ".mode", &value))
452         MAIN_ParseModeOption( (char *)value.addr );
453
454 #ifdef DEBUG_RUNTIME
455     if (MAIN_GetResource( db, ".debugoptions", &value))
456         ParseDebugOptions((char*)value.addr);
457 #endif
458     if (MAIN_GetResource( db, ".debugmsg", &value))
459       {
460 #ifndef DEBUG_RUNTIME
461         fprintf(stderr,"%s: Option \"-debugmsg\" not implemented.\n" \
462           "    Recompile with DEBUG_RUNTIME in include/stddebug.h defined.\n",
463           argv[0]);
464         exit(1);
465 #else
466         if (ParseDebugOptions((char*)value.addr)==FALSE)
467           {
468             int i;
469             fprintf(stderr,"%s: Syntax: -debugmsg +xxx,...  or -debugmsg -xxx,...\n",argv[0]);
470             fprintf(stderr,"Example: -debugmsg +all,-heap    turn on all messages except heap messages\n");
471             fprintf(stderr,"Available message types:\n");
472             fprintf(stderr,"%-9s ","all");
473             for(i=0;i<sizeof(debug_msg_enabled)/sizeof(short);i++)
474               if(debug_msg_name[i])
475                 fprintf(stderr,"%-9s%c",debug_msg_name[i],
476                         (((i+2)%8==0)?'\n':' '));
477             fprintf(stderr,"\n\n");
478             exit(1);
479           }
480 #endif
481       }
482
483       if(MAIN_GetResource( db, ".dll", &value))
484       {
485 #ifndef WINELIB
486           if (!BUILTIN_ParseDLLOptions( (char*)value.addr ))
487           {
488               fprintf(stderr,"%s: Syntax: -dll +xxx,... or -dll -xxx,...\n",argv[0]);
489               fprintf(stderr,"Example: -dll -ole2    Do not use emulated OLE2.DLL\n");
490               fprintf(stderr,"Available DLLs:\n");
491               BUILTIN_PrintDLLs();
492               exit(1);
493           }
494 #else
495           fprintf(stderr,"-dll not supported in libwine\n");
496 #endif
497       }
498
499       if(MAIN_GetResource( db, ".winver", &value))
500           MAIN_ParseVersion( (char*)value.addr );
501 }
502
503
504 /***********************************************************************
505  *           MAIN_CreateDesktop
506  */
507 static void MAIN_CreateDesktop( int argc, char *argv[] )
508 {
509     int flags;
510     unsigned int width = 640, height = 480;  /* Default size = 640x480 */
511     char *name = "Wine desktop";
512     XSizeHints *size_hints;
513     XWMHints   *wm_hints;
514     XClassHint *class_hints;
515     XSetWindowAttributes win_attr;
516     XTextProperty window_name;
517     Atom XA_WM_DELETE_WINDOW;
518
519     flags = XParseGeometry( Options.desktopGeometry,
520                             &desktopX, &desktopY, &width, &height );
521     screenWidth  = width;
522     screenHeight = height;
523
524       /* Create window */
525
526     win_attr.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask |
527                          PointerMotionMask | ButtonPressMask |
528                          ButtonReleaseMask | EnterWindowMask | 
529                          StructureNotifyMask;
530     win_attr.cursor = XCreateFontCursor( display, XC_top_left_arrow );
531
532     rootWindow = XCreateWindow( display, DefaultRootWindow(display),
533                                 desktopX, desktopY, width, height, 0,
534                                 CopyFromParent, InputOutput, CopyFromParent,
535                                 CWEventMask | CWCursor, &win_attr );
536
537       /* Set window manager properties */
538
539     size_hints  = XAllocSizeHints();
540     wm_hints    = XAllocWMHints();
541     class_hints = XAllocClassHint();
542     if (!size_hints || !wm_hints || !class_hints)
543     {
544         fprintf( stderr, "Not enough memory for window manager hints.\n" );
545         exit(1);
546     }
547     size_hints->min_width = size_hints->max_width = width;
548     size_hints->min_height = size_hints->max_height = height;
549     size_hints->flags = PMinSize | PMaxSize;
550     if (flags & (XValue | YValue)) size_hints->flags |= USPosition;
551     if (flags & (WidthValue | HeightValue)) size_hints->flags |= USSize;
552     else size_hints->flags |= PSize;
553
554     wm_hints->flags = InputHint | StateHint;
555     wm_hints->input = True;
556     wm_hints->initial_state = NormalState;
557     class_hints->res_name = argv[0];
558     class_hints->res_class = "Wine";
559
560     XStringListToTextProperty( &name, 1, &window_name );
561     XSetWMProperties( display, rootWindow, &window_name, &window_name,
562                       argv, argc, size_hints, wm_hints, class_hints );
563     XA_WM_DELETE_WINDOW = XInternAtom( display, "WM_DELETE_WINDOW", False );
564     XSetWMProtocols( display, rootWindow, &XA_WM_DELETE_WINDOW, 1 );
565     XFree( size_hints );
566     XFree( wm_hints );
567     XFree( class_hints );
568
569       /* Map window */
570
571     XMapWindow( display, rootWindow );
572 }
573
574
575 XKeyboardState keyboard_state;
576
577 /***********************************************************************
578  *           MAIN_SaveSetup
579  */
580 static void MAIN_SaveSetup(void)
581 {
582     XGetKeyboardControl(display, &keyboard_state);
583 }
584
585 /***********************************************************************
586  *           MAIN_RestoreSetup
587  */
588 static void MAIN_RestoreSetup(void)
589 {
590     XKeyboardControl keyboard_value;
591
592     keyboard_value.key_click_percent    = keyboard_state.key_click_percent;
593     keyboard_value.bell_percent         = keyboard_state.bell_percent;
594     keyboard_value.bell_pitch           = keyboard_state.bell_pitch;
595     keyboard_value.bell_duration        = keyboard_state.bell_duration;
596     keyboard_value.auto_repeat_mode     = keyboard_state.global_auto_repeat;
597
598     XChangeKeyboardControl(display, KBKeyClickPercent | KBBellPercent | 
599         KBBellPitch | KBBellDuration | KBAutoRepeatMode, &keyboard_value);
600 }
601
602
603 static void called_at_exit(void)
604 {
605     MAIN_RestoreSetup();
606     COLOR_Cleanup();
607     WINSOCK_Shutdown();
608 }
609
610 /***********************************************************************
611  *           MAIN_WineInit
612  *
613  * Wine initialisation and command-line parsing
614  */
615 BOOL32 MAIN_WineInit( int *argc, char *argv[] )
616 {    
617     int depth_count, i;
618     int *depth_list;
619     struct timeval tv;
620
621     extern int _WinMain(int argc, char **argv);
622
623 #ifdef MALLOC_DEBUGGING
624     char *trace;
625
626     mcheck(NULL);
627     if (!(trace = getenv("MALLOC_TRACE")))
628     {       
629         fprintf( stderr, "MALLOC_TRACE not set. No trace generated\n" );
630     }
631     else
632     {
633         fprintf( stderr, "malloc trace goes to %s\n", trace );
634         mtrace();
635     }
636 #endif
637
638     setbuf(stdout,NULL);
639     setbuf(stderr,NULL);
640
641     setlocale(LC_CTYPE,"");
642     gettimeofday( &tv, NULL);
643     MSG_WineStartTicks = (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
644
645     XrmInitialize();
646
647     putenv("XKB_DISABLE="); /* Disable XKB extension if present. */
648
649     MAIN_ParseOptions( argc, argv );
650
651     if (Options.desktopGeometry && Options.managed)
652     {
653         fprintf( stderr, "%s: -managed and -desktop options cannot be used together\n",
654                  Options.programName );
655         exit(1);
656     }
657
658     screen       = DefaultScreenOfDisplay( display );
659     screenWidth  = WidthOfScreen( screen );
660     screenHeight = HeightOfScreen( screen );
661     if (screenDepth)  /* -depth option specified */
662     {
663         depth_list = XListDepths(display,DefaultScreen(display),&depth_count);
664         for (i = 0; i < depth_count; i++)
665             if (depth_list[i] == screenDepth) break;
666         XFree( depth_list );
667         if (i >= depth_count)
668         {
669             fprintf( stderr, "%s: Depth %d not supported on this screen.\n",
670                               Options.programName, screenDepth );
671             exit(1);
672         }
673     }
674     else screenDepth  = DefaultDepthOfScreen( screen );
675     if (Options.synchronous) XSynchronize( display, True );
676     if (Options.desktopGeometry) MAIN_CreateDesktop( *argc, argv );
677     else rootWindow = DefaultRootWindow( display );
678
679     MAIN_SaveSetup();
680     atexit(called_at_exit);
681     return TRUE;
682 }
683
684
685 /***********************************************************************
686  *           MessageBeep16   (USER.104)
687  */
688 void MessageBeep16( UINT16 i )
689 {
690     MessageBeep32( i );
691 }
692
693
694 /***********************************************************************
695  *           MessageBeep32   (USER32.389)
696  */
697 BOOL32 MessageBeep32( UINT32 i )
698 {
699     XBell( display, 100 );
700     return TRUE;
701 }
702
703
704 /***********************************************************************
705  *           Beep   (KERNEL32.11)
706  */
707 BOOL32 Beep( DWORD dwFreq, DWORD dwDur )
708 {
709     /* dwFreq and dwDur are ignored by Win95 */
710     XBell(display, 100);
711     return TRUE;
712 }
713
714
715 /***********************************************************************
716  *      GetVersion16   (KERNEL.3)
717  */
718 LONG GetVersion16(void)
719 {
720     if (getVersion16) return getVersion16;
721     return MAKELONG( WINVERSION, WINDOSVER );
722 }
723
724
725 /***********************************************************************
726  *      GetVersion32
727  */
728 LONG GetVersion32(void)
729 {
730     if (getVersion32) return getVersion32;
731     return MAKELONG( 4, DOSVERSION);
732 }
733
734
735 /***********************************************************************
736  *      GetVersionExA
737  */
738 BOOL32 GetVersionEx32A(OSVERSIONINFO32A *v)
739 {
740     if(v->dwOSVersionInfoSize!=sizeof(OSVERSIONINFO32A))
741     {
742         fprintf(stddeb,"wrong OSVERSIONINFO size from app");
743         return FALSE;
744     }
745     if(!getVersion32)
746     {
747         /* Return something like NT 3.5 */
748         v->dwMajorVersion = 3;
749         v->dwMinorVersion = 5;
750         v->dwBuildNumber = 42;
751         v->dwPlatformId = VER_PLATFORM_WIN32_NT;
752         strcpy(v->szCSDVersion, "Wine is not an emulator");
753         return TRUE;
754     }
755     v->dwMajorVersion = getVersionEx.dwMajorVersion;
756     v->dwMinorVersion = getVersionEx.dwMinorVersion;
757     v->dwBuildNumber = getVersionEx.dwBuildNumber;
758     v->dwPlatformId = getVersionEx.dwPlatformId;
759     strcpy(v->szCSDVersion, getVersionEx.szCSDVersion);
760     return TRUE;
761 }
762
763
764 /***********************************************************************
765  *     GetVersionExW
766  */
767 BOOL32 GetVersionEx32W(OSVERSIONINFO32W *v)
768 {
769         OSVERSIONINFO32A v1;
770         if(v->dwOSVersionInfoSize!=sizeof(OSVERSIONINFO32W))
771         {
772                 fprintf(stddeb,"wrong OSVERSIONINFO size from app");
773                 return FALSE;
774         }
775         v1.dwOSVersionInfoSize=sizeof(v1);
776         GetVersionEx32A(&v1);
777         v->dwMajorVersion = v1.dwMajorVersion;
778         v->dwMinorVersion = v1.dwMinorVersion;
779         v->dwBuildNumber = v1.dwBuildNumber;
780         v->dwPlatformId = v1.dwPlatformId;
781         lstrcpyAtoW( v->szCSDVersion, v1.szCSDVersion );
782         return TRUE;
783 }
784
785 /***********************************************************************
786  *      GetWinFlags (KERNEL.132)
787  */
788 DWORD GetWinFlags(void)
789 {
790   static const long cpuflags[5] =
791     { WF_CPU086, WF_CPU186, WF_CPU286, WF_CPU386, WF_CPU486 };
792   SYSTEM_INFO   si;
793   long result = 0,cpuflag;
794
795   GetSystemInfo(&si);
796
797   /* There doesn't seem to be any Pentium flag.  */
798   cpuflag = cpuflags[MIN (si.wProcessorLevel, 4)];
799
800   switch(Options.mode) {
801   case MODE_STANDARD:
802     result = (WF_STANDARD | cpuflag | WF_PMODE | WF_80x87);
803     break;
804
805   case MODE_ENHANCED:
806     result = (WF_ENHANCED | cpuflag | WF_PMODE | WF_80x87 | WF_PAGING);
807     break;
808
809   default:
810     fprintf(stderr, "Unknown mode set? This shouldn't happen. Check GetWinFlags()!\n");
811     break;
812   }
813   if( getVersionEx.dwPlatformId == VER_PLATFORM_WIN32_NT )
814       result |= 0x4000; /* undocumented WF_WINNT */
815   return result;
816 }
817
818 /***********************************************************************
819  *      SetEnvironment (GDI.132)
820  */
821 int SetEnvironment(LPCSTR lpPortName, LPCSTR lpEnviron, WORD nCount)
822 {
823     LPENVENTRY  lpNewEnv;
824     LPENVENTRY  lpEnv = lpEnvList;
825     dprintf_env(stddeb, "SetEnvironment('%s', '%s', %d) !\n", 
826                 lpPortName, lpEnviron, nCount);
827     if (lpPortName == NULL) return -1;
828     while (lpEnv != NULL) {
829         if (lpEnv->Name != NULL && strcmp(lpEnv->Name, lpPortName) == 0) {
830             if (nCount == 0 || lpEnviron == NULL) {
831                 if (lpEnv->Prev != NULL) lpEnv->Prev->Next = lpEnv->Next;
832                 if (lpEnv->Next != NULL) lpEnv->Next->Prev = lpEnv->Prev;
833                 free(lpEnv->Value);
834                 free(lpEnv->Name);
835                 free(lpEnv);
836                 dprintf_env(stddeb, "SetEnvironment() // entry deleted !\n");
837                 return -1;
838             }
839             free(lpEnv->Value);
840             lpEnv->Value = malloc(nCount);
841             if (lpEnv->Value == NULL) {
842                 dprintf_env(stddeb, "SetEnvironment() // Error allocating entry value !\n");
843                 return 0;
844             }
845             memcpy(lpEnv->Value, lpEnviron, nCount);
846             lpEnv->wSize = nCount;
847             dprintf_env(stddeb, "SetEnvironment() // entry modified !\n");
848             return nCount;
849         }
850         if (lpEnv->Next == NULL) break;
851         lpEnv = lpEnv->Next;
852     }
853     if (nCount == 0 || lpEnviron == NULL) return -1;
854     dprintf_env(stddeb, "SetEnvironment() // new entry !\n");
855     lpNewEnv = malloc(sizeof(ENVENTRY));
856     if (lpNewEnv == NULL) {
857         dprintf_env(stddeb, "SetEnvironment() // Error allocating new entry !\n");
858         return 0;
859     }
860     if (lpEnvList == NULL) {
861         lpEnvList = lpNewEnv;
862         lpNewEnv->Prev = NULL;
863     }
864     else 
865     {
866         lpEnv->Next = lpNewEnv;
867         lpNewEnv->Prev = lpEnv;
868     }
869     lpNewEnv->Next = NULL;
870     lpNewEnv->Name = malloc(strlen(lpPortName) + 1);
871     if (lpNewEnv->Name == NULL) {
872         dprintf_env(stddeb, "SetEnvironment() // Error allocating entry name !\n");
873         return 0;
874     }
875     strcpy(lpNewEnv->Name, lpPortName);
876     lpNewEnv->Value = malloc(nCount);
877     if (lpNewEnv->Value == NULL) {
878         dprintf_env(stddeb, "SetEnvironment() // Error allocating entry value !\n");
879         return 0;
880     }
881     memcpy(lpNewEnv->Value, lpEnviron, nCount);
882     lpNewEnv->wSize = nCount;
883     return nCount;
884 }
885
886
887 /***********************************************************************
888  *      GetEnvironment (GDI.134)
889  */
890 int GetEnvironment(LPSTR lpPortName, LPSTR lpEnviron, WORD nMaxSiz)
891 {
892     WORD       nCount;
893     LPENVENTRY lpEnv = lpEnvList;
894
895     dprintf_env(stddeb, "GetEnvironment('%s', '%s', %d) !\n",
896                 lpPortName, lpEnviron, nMaxSiz);
897     while (lpEnv != NULL) {
898         if (lpEnv->Name != NULL && strcmp(lpEnv->Name, lpPortName) == 0) {
899             if( lpEnviron == NULL ) return lpEnv->wSize;
900             nCount = MIN(nMaxSiz, lpEnv->wSize);
901             memcpy(lpEnviron, lpEnv->Value, nCount);
902             dprintf_env(stddeb, "GetEnvironment() // found '%s' !\n", lpEnv->Value);
903             return nCount;
904         }
905         lpEnv = lpEnv->Next;
906     }
907     dprintf_env(stddeb, "GetEnvironment() // not found !\n");
908     return 0;
909 }
910
911
912 /***********************************************************************
913  *      GetTimerResolution (USER.14)
914  */
915 LONG GetTimerResolution(void)
916 {
917         return (1000);
918 }
919
920 /***********************************************************************
921  *      SystemParametersInfo32A   (USER32.539)
922  */
923 BOOL32 SystemParametersInfo32A( UINT32 uAction, UINT32 uParam,
924                                 LPVOID lpvParam, UINT32 fuWinIni )
925 {
926     return SystemParametersInfo16(uAction,uParam,lpvParam,fuWinIni);
927 }
928
929
930 /***********************************************************************
931  *      SystemParametersInfo16   (USER.483)
932  */
933 BOOL16 SystemParametersInfo16( UINT16 uAction, UINT16 uParam,
934                                LPVOID lpvParam, UINT16 fuWinIni )
935 {
936         int timeout, temp;
937         char buffer[256];
938         XKeyboardState          keyboard_state;
939         XKeyboardControl        keyboard_value;
940
941
942         switch (uAction)
943         {
944                 case SPI_GETBEEP:
945                         XGetKeyboardControl(display, &keyboard_state);
946                         if (keyboard_state.bell_percent == 0)
947                                 *(BOOL *) lpvParam = FALSE;
948                         else
949                                 *(BOOL *) lpvParam = TRUE;
950                         break;
951                 
952                 case SPI_GETBORDER:
953                         *(INT16 *)lpvParam = GetSystemMetrics16( SM_CXFRAME );
954                         break;
955
956                 case SPI_GETFASTTASKSWITCH:
957                     if ( GetProfileInt32A( "windows", "CoolSwitch", 1 ) == 1 )
958                           *(BOOL *) lpvParam = TRUE;
959                         else
960                           *(BOOL *) lpvParam = FALSE;
961                         break;
962
963                 case SPI_GETGRIDGRANULARITY:
964                     *(INT *) lpvParam = GetProfileInt32A( "desktop", 
965                                                           "GridGranularity",
966                                                           1 );
967                     break;
968
969                 case SPI_GETICONTITLEWRAP:
970                     *(BOOL *) lpvParam = GetProfileInt32A( "desktop",
971                                                            "IconTitleWrap",
972                                                            TRUE );
973                     break;
974
975                 case SPI_GETKEYBOARDDELAY:
976                     *(INT *) lpvParam = GetProfileInt32A( "keyboard",
977                                                           "KeyboardDelay", 1 );
978                     break;
979
980                 case SPI_GETKEYBOARDSPEED:
981                     *(WORD *) lpvParam = GetProfileInt32A( "keyboard",
982                                                            "KeyboardSpeed",
983                                                            30 );
984                     break;
985
986                 case SPI_GETMENUDROPALIGNMENT:
987                         *(BOOL16 *) lpvParam = GetSystemMetrics16( SM_MENUDROPALIGNMENT ); /* XXX check this */
988                         break;
989
990                 case SPI_GETSCREENSAVEACTIVE:
991                     if ( GetProfileInt32A( "windows", "ScreenSaveActive", 1 ) == 1 )
992                         *(BOOL *) lpvParam = TRUE;
993                     else
994                         *(BOOL *) lpvParam = FALSE;
995                     break;
996
997                 case SPI_GETSCREENSAVETIMEOUT:
998                         /* FIXME GetProfileInt( "windows", "ScreenSaveTimeout", 300 ); */
999                         XGetScreenSaver(display, &timeout, &temp,&temp,&temp);
1000                         *(INT *) lpvParam = timeout * 1000;
1001                         break;
1002
1003                 case SPI_ICONHORIZONTALSPACING:
1004                     /* FIXME Get/SetProfileInt */
1005                         if (lpvParam == NULL)
1006                             /*SetSystemMetrics( SM_CXICONSPACING, uParam )*/ ;
1007                         else
1008                             *(INT16 *)lpvParam = GetSystemMetrics16( SM_CXICONSPACING );
1009                         break;
1010
1011                 case SPI_ICONVERTICALSPACING:
1012                     /* FIXME Get/SetProfileInt */
1013                     if (lpvParam == NULL)
1014                         /*SetSystemMetrics( SM_CYICONSPACING, uParam )*/ ;
1015                     else
1016                         *(INT16 *)lpvParam = GetSystemMetrics16(SM_CYICONSPACING);
1017                     break;
1018
1019                 case SPI_SETBEEP:
1020                         if (uParam == TRUE)
1021                                 keyboard_value.bell_percent = -1;
1022                         else
1023                                 keyboard_value.bell_percent = 0;                        
1024                         XChangeKeyboardControl(display, KBBellPercent, 
1025                                                         &keyboard_value);
1026                         break;
1027
1028                 case SPI_SETSCREENSAVEACTIVE:
1029                         if (uParam == TRUE)
1030                                 XActivateScreenSaver(display);
1031                         else
1032                                 XResetScreenSaver(display);
1033                         break;
1034
1035                 case SPI_SETSCREENSAVETIMEOUT:
1036                         XSetScreenSaver(display, uParam, 60, DefaultBlanking, 
1037                                                         DefaultExposures);
1038                         break;
1039
1040                 case SPI_SETDESKWALLPAPER:
1041                         return (SetDeskWallPaper32((LPSTR) lpvParam));
1042                         break;
1043
1044                 case SPI_SETDESKPATTERN:
1045                         if ((INT16)uParam == -1) {
1046                                 GetProfileString32A("Desktop", "Pattern", 
1047                                                 "170 85 170 85 170 85 170 85", 
1048                                                 buffer, sizeof(buffer) );
1049                                 return (DESKTOP_SetPattern((LPSTR) buffer));
1050                         } else
1051                                 return (DESKTOP_SetPattern((LPSTR) lpvParam));
1052                         break;
1053
1054                 case SPI_GETICONTITLELOGFONT: 
1055                 {
1056                     /* FIXME GetProfileString32A( "?", "?", "?" ) */
1057                     LPLOGFONT16 lpLogFont = (LPLOGFONT16)lpvParam;
1058                     lpLogFont->lfHeight = 10;
1059                     lpLogFont->lfWidth = 0;
1060                     lpLogFont->lfEscapement = lpLogFont->lfOrientation = 0;
1061                     lpLogFont->lfWeight = FW_NORMAL;
1062                     lpLogFont->lfItalic = FALSE;
1063                     lpLogFont->lfStrikeOut = FALSE;
1064                     lpLogFont->lfUnderline = FALSE;
1065                     lpLogFont->lfCharSet = ANSI_CHARSET;
1066                     lpLogFont->lfOutPrecision = OUT_DEFAULT_PRECIS;
1067                     lpLogFont->lfClipPrecision = CLIP_DEFAULT_PRECIS;
1068                     lpLogFont->lfPitchAndFamily = DEFAULT_PITCH | FF_SWISS;
1069                     break;
1070                 }
1071
1072                 case SPI_LANGDRIVER:
1073                 case SPI_SETBORDER:
1074                 case SPI_SETDOUBLECLKHEIGHT:
1075                 case SPI_SETDOUBLECLICKTIME:
1076                 case SPI_SETDOUBLECLKWIDTH:
1077                 case SPI_SETFASTTASKSWITCH:
1078                 case SPI_SETKEYBOARDDELAY:
1079                 case SPI_SETKEYBOARDSPEED:
1080                         fprintf(stderr, "SystemParametersInfo: option %d ignored.\n", uAction);
1081                         break;
1082
1083                 case SPI_GETWORKAREA:
1084                     SetRect16( (RECT16 *)lpvParam, 0, 0,
1085                                GetSystemMetrics16( SM_CXSCREEN ),
1086                                GetSystemMetrics16( SM_CYSCREEN ) );
1087                     break;
1088
1089                 default:
1090                         fprintf(stderr, "SystemParametersInfo: unknown option %d.\n", uAction);
1091                         break;
1092         }
1093         return 1;
1094 }
1095
1096 /***********************************************************************
1097  *      SystemParametersInfo32W   (USER32.540)
1098  */
1099 BOOL32 SystemParametersInfo32W( UINT32 uAction, UINT32 uParam,
1100                                 LPVOID lpvParam, UINT32 fuWinIni )
1101 {
1102     char buffer[256];
1103
1104     switch (uAction)
1105     {
1106     case SPI_SETDESKWALLPAPER:
1107         if (lpvParam)
1108         {
1109             lstrcpynWtoA(buffer,(LPWSTR)lpvParam,sizeof(buffer));
1110             return SetDeskWallPaper32(buffer);
1111         }
1112         return SetDeskWallPaper32(NULL);
1113
1114     case SPI_SETDESKPATTERN:
1115         if ((INT) uParam == -1)
1116         {
1117             GetProfileString32A("Desktop", "Pattern", 
1118                                 "170 85 170 85 170 85 170 85", 
1119                                 buffer, sizeof(buffer) );
1120             return (DESKTOP_SetPattern((LPSTR) buffer));
1121         }
1122         if (lpvParam)
1123         {
1124             lstrcpynWtoA(buffer,(LPWSTR)lpvParam,sizeof(buffer));
1125             return DESKTOP_SetPattern(buffer);
1126         }
1127         return DESKTOP_SetPattern(NULL);
1128
1129     case SPI_GETICONTITLELOGFONT:
1130         {
1131             /* FIXME GetProfileString32A( "?", "?", "?" ) */
1132             LPLOGFONT32W lpLogFont = (LPLOGFONT32W)lpvParam;
1133             lpLogFont->lfHeight = 10;
1134             lpLogFont->lfWidth = 0;
1135             lpLogFont->lfEscapement = lpLogFont->lfOrientation = 0;
1136             lpLogFont->lfWeight = FW_NORMAL;
1137             lpLogFont->lfItalic = lpLogFont->lfStrikeOut = lpLogFont->lfUnderline = FALSE;
1138             lpLogFont->lfCharSet = ANSI_CHARSET;
1139             lpLogFont->lfOutPrecision = OUT_DEFAULT_PRECIS;
1140             lpLogFont->lfClipPrecision = CLIP_DEFAULT_PRECIS;
1141             lpLogFont->lfPitchAndFamily = DEFAULT_PITCH | FF_SWISS;
1142         }
1143         break;
1144
1145     default:
1146         return SystemParametersInfo32A(uAction,uParam,lpvParam,fuWinIni);
1147         
1148     }
1149     return TRUE;
1150 }
1151
1152
1153 /***********************************************************************
1154 *       FileCDR (KERNEL.130)
1155 */
1156 void FileCDR(FARPROC16 x)
1157 {
1158         printf("FileCDR(%8x)\n", (int) x);
1159 }
1160
1161 /***********************************************************************
1162 *       GetWinDebugInfo (KERNEL.355)
1163 */
1164 BOOL16 GetWinDebugInfo(WINDEBUGINFO *lpwdi, UINT16 flags)
1165 {
1166         printf("GetWinDebugInfo(%8lx,%d) stub returning 0\n", (unsigned long)lpwdi, flags);
1167         /* 0 means not in debugging mode/version */
1168         /* Can this type of debugging be used in wine ? */
1169         /* Constants: WDI_OPTIONS WDI_FILTER WDI_ALLOCBREAK */
1170         return 0;
1171 }
1172
1173 /***********************************************************************
1174 *       GetWinDebugInfo (KERNEL.355)
1175 */
1176 BOOL16 SetWinDebugInfo(WINDEBUGINFO *lpwdi)
1177 {
1178         printf("SetWinDebugInfo(%8lx) stub returning 0\n", (unsigned long)lpwdi);
1179         /* 0 means not in debugging mode/version */
1180         /* Can this type of debugging be used in wine ? */
1181         /* Constants: WDI_OPTIONS WDI_FILTER WDI_ALLOCBREAK */
1182         return 0;
1183 }