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