Initial release of Maemo 5 port of gnuplot
[gnuplot] / src / win / winmain.c
1 #ifndef lint
2 static char *RCSid() { return RCSid("$Id: winmain.c,v 1.22.2.1 2007/03/22 05:08:26 sfeam Exp $"); }
3 #endif
4
5 /* GNUPLOT - win/winmain.c */
6 /*[
7  * Copyright 1992, 1993, 1998, 2004   Maurice Castro, Russell Lang
8  *
9  * Permission to use, copy, and distribute this software and its
10  * documentation for any purpose with or without fee is hereby granted,
11  * provided that the above copyright notice appear in all copies and
12  * that both that copyright notice and this permission notice appear
13  * in supporting documentation.
14  *
15  * Permission to modify the software is granted, but not the right to
16  * distribute the complete modified source code.  Modifications are to
17  * be distributed as patches to the released version.  Permission to
18  * distribute binaries produced by compiling modified sources is granted,
19  * provided you
20  *   1. distribute the corresponding source modifications from the
21  *    released version in the form of a patch file along with the binaries,
22  *   2. add special version identification to distinguish your version
23  *    in addition to the base release version number,
24  *   3. provide your name and address as the primary contact for the
25  *    support of your modified version, and
26  *   4. retain our contact information in regard to use of the base
27  *    software.
28  * Permission to distribute the released version of the source code along
29  * with corresponding source modifications in the form of a patch file is
30  * granted with same provisions 2 through 4 for binary distributions.
31  *
32  * This software is provided "as is" without express or implied warranty
33  * to the extent permitted by applicable law.
34 ]*/
35
36 /*
37  * AUTHORS
38  *
39  *   Maurice Castro
40  *   Russell Lang
41  *
42  */
43
44 /* This file implements the initialization code for running gnuplot   */
45 /* under Microsoft Windows. The code currently compiles only with the */
46 /* Borland C++ 3.1 compiler.                                          */
47 /*                                                                    */
48 /* The modifications to allow Gnuplot to run under Windows were made  */
49 /* by Maurice Castro. (maurice@bruce.cs.monash.edu.au)  3 Jul 1992    */
50 /* and Russell Lang (rjl@monu1.cc.monash.edu.au) 30 Nov 1992          */
51 /*                                                                    */
52
53 #ifdef HAVE_CONFIG_H
54 # include "config.h"
55 #endif
56 #define STRICT
57 #include <windows.h>
58 #include <windowsx.h>
59 #include <dos.h>
60 #include <stdio.h>
61 #include <stdlib.h>
62 #include <string.h>
63 #include <stdarg.h>
64 #include <ctype.h>
65 #ifdef __MSC__
66 # include <malloc.h>
67 #endif
68 #ifdef __TURBOC__ /* HBB 981201: MinGW32 doesn't have this */
69 # include <alloc.h>
70 #endif
71 #ifdef __WATCOMC__
72 # define mktemp _mktemp
73 #endif
74 #include <io.h>
75 #include "plot.h"
76 #include "setshow.h"
77 #include "version.h"
78 #include "wgnuplib.h"
79 #include "wtext.h"
80 #include "wcommon.h"
81
82 #ifdef WIN32
83 # ifndef _WIN32_IE
84 #  define _WIN32_IE 0x0400
85 # endif 
86 # include <shlobj.h>
87 # include <shlwapi.h>
88   /* workaround for old header files */
89 # ifndef CSIDL_APPDATA 
90 #  define CSIDL_APPDATA (0x001a)
91 # endif
92 #endif
93
94 /* limits */
95 #define MAXSTR 255
96 #define MAXPRINTF 1024
97
98 /* globals */
99 TW textwin;
100 GW graphwin;
101 PW pausewin;
102 MW menuwin;
103 LPSTR szModuleName;
104 LPSTR winhelpname;
105 LPSTR szMenuName;
106 #define MENUNAME "wgnuplot.mnu"
107 #ifndef HELPFILE /* HBB 981203: makefile.win predefines this... */
108 #define HELPFILE "wgnuplot.hlp"
109 #endif
110
111 char *authors[]={
112                  "Colin Kelley",
113                  "Thomas Williams"
114                 };
115
116 void WinExit(void);
117 int gnu_main(int argc, char *argv[], char *env[]);
118
119 void
120 CheckMemory(LPSTR str)
121 {
122         if (str == (LPSTR)NULL) {
123                 MessageBox(NULL, "out of memory", "gnuplot", MB_ICONSTOP | MB_OK);
124                 exit(1);
125         }
126 }
127
128 int
129 Pause(LPSTR str)
130 {
131         pausewin.Message = str;
132         return (PauseBox(&pausewin) == IDOK);
133 }
134
135 void
136 kill_pending_Pause_dialog ()
137 {
138         if (pausewin.bPause == FALSE) /* no Pause dialog displayed */
139             return;
140         /* Pause dialog displayed, thus kill it */
141         DestroyWindow(pausewin.hWndPause);
142 #ifndef WIN32
143 #ifndef __DLL__
144         FreeProcInstance((FARPROC)pausewin.lpfnPauseButtonProc);
145 #endif
146 #endif
147         pausewin.bPause = FALSE;
148 }
149
150 /* atexit procedure */
151 void
152 WinExit()
153 {
154         term_reset();
155
156 #ifndef __MINGW32__ /* HBB 980809: FIXME: doesn't exist for MinGW32. So...? */
157         fcloseall();
158 #endif
159         if (graphwin.hWndGraph && IsWindow(graphwin.hWndGraph))
160                 GraphClose(&graphwin);
161         TextMessage();  /* process messages */
162         WinHelp(textwin.hWndText,(LPSTR)winhelpname,HELP_QUIT,(DWORD)NULL);
163         TextClose(&textwin);
164         TextMessage();  /* process messages */
165         return;
166 }
167
168 /* call back function from Text Window WM_CLOSE */
169 int CALLBACK WINEXPORT
170 ShutDown()
171 {
172         exit(0);
173         return 0;
174 }
175
176 #ifdef WIN32
177
178 /* This function can be used to retrieve version information from
179  * Window's Shell and common control libraries such (Comctl32.dll,
180  * Shell32.dll, and Shlwapi.dll) The code was copied from the MSDN
181  * article "Shell and Common Controls Versions" */
182 DWORD
183 GetDllVersion(LPCTSTR lpszDllName)
184 {
185     HINSTANCE hinstDll;
186     DWORD dwVersion = 0;
187
188     /* For security purposes, LoadLibrary should be provided with a 
189        fully-qualified path to the DLL. The lpszDllName variable should be
190        tested to ensure that it is a fully qualified path before it is used. */
191     hinstDll = LoadLibrary(lpszDllName);
192         
193     if (hinstDll) {
194         DLLGETVERSIONPROC pDllGetVersion;
195         pDllGetVersion = (DLLGETVERSIONPROC)GetProcAddress(hinstDll, 
196                           "DllGetVersion");
197
198         /* Because some DLLs might not implement this function, you
199         must test for it explicitly. Depending on the particular 
200         DLL, the lack of a DllGetVersion function can be a useful
201         indicator of the version. */
202         if (pDllGetVersion) {
203             DLLVERSIONINFO dvi;
204             HRESULT hr;
205
206             ZeroMemory(&dvi, sizeof(dvi));
207             dvi.cbSize = sizeof(dvi);
208             hr = (*pDllGetVersion)(&dvi);
209             if (SUCCEEDED(hr))
210                dwVersion = PACKVERSION(dvi.dwMajorVersion, dvi.dwMinorVersion);
211         }
212         FreeLibrary(hinstDll);
213     }
214     return dwVersion;
215 }
216
217
218 char *
219 appdata_directory(void)
220 {
221     HMODULE hShell32; 
222     FARPROC pSHGetSpecialFolderPath;
223     static char dir[MAX_PATH] = "";
224
225     if (dir[0])
226         return dir;
227
228     /* Make sure that SHGetSpecialFolderPath is supported. */
229     hShell32 = LoadLibrary(TEXT("shell32.dll"));
230     if (hShell32) {
231         pSHGetSpecialFolderPath =
232             GetProcAddress(hShell32, 
233                            TEXT("SHGetSpecialFolderPathA"));
234         if (pSHGetSpecialFolderPath)
235             (*pSHGetSpecialFolderPath)(NULL, dir, CSIDL_APPDATA, FALSE);
236         FreeModule(hShell32);
237         return dir;
238     }
239
240     /* use APPDATA environment variable as fallback */
241     if (dir[0] == '\0') {
242         char *appdata = getenv("APPDATA");
243         if (appdata) {
244             strcpy(dir, appdata);
245             return dir;
246         }
247     }
248
249     return NULL;
250 }
251
252 #endif /* WIN32 */
253
254 int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
255                 LPSTR lpszCmdLine, int nCmdShow)
256 {
257         /*WNDCLASS wndclass;*/
258         LPSTR tail;
259
260 #ifdef __MSC__  /* MSC doesn't give us _argc and _argv[] so ...   */
261 # ifdef WIN32    /* WIN32 has __argc and __argv */
262 #  define _argv __argv
263 #  define _argc __argc
264 # else
265 #  define MAXCMDTOKENS 128
266         int     _argc=0;
267         LPSTR   _argv[MAXCMDTOKENS];
268         _argv[_argc] = "wgnuplot.exe";
269         _argv[++_argc] = _fstrtok( lpszCmdLine, " ");
270         while (_argv[_argc] != NULL)
271                 _argv[++_argc] = _fstrtok( NULL, " ");
272 # endif /* WIN32 */
273 #endif /* __MSC__ */
274
275 #ifdef  __WATCOMC__
276 # define _argv __argv
277 # define _argc __argc
278 #endif
279
280         szModuleName = (LPSTR)farmalloc(MAXSTR+1);
281         CheckMemory(szModuleName);
282
283         /* get path to EXE */
284         GetModuleFileName(hInstance, (LPSTR) szModuleName, MAXSTR);
285 #ifndef WIN32
286         if (CheckWGNUPLOTVersion(WGNUPLOTVERSION)) {
287                 MessageBox(NULL, "Wrong version of WGNUPLOT.DLL", szModuleName, MB_ICONSTOP | MB_OK);
288                 exit(1);
289         }
290 #endif
291         if ((tail = (LPSTR)_fstrrchr(szModuleName,'\\')) != (LPSTR)NULL)
292         {
293                 tail++;
294                 *tail = 0;
295         }
296         szModuleName = (LPSTR)farrealloc(szModuleName, _fstrlen(szModuleName)+1);
297         CheckMemory(szModuleName);
298
299         winhelpname = (LPSTR)farmalloc(_fstrlen(szModuleName)+_fstrlen(HELPFILE)+1);
300         CheckMemory(winhelpname);
301         _fstrcpy(winhelpname,szModuleName);
302         _fstrcat(winhelpname,HELPFILE);
303
304         szMenuName = (LPSTR)farmalloc(_fstrlen(szModuleName)+_fstrlen(MENUNAME)+1);
305         CheckMemory(szMenuName);
306         _fstrcpy(szMenuName,szModuleName);
307         _fstrcat(szMenuName,MENUNAME);
308
309         textwin.hInstance = hInstance;
310         textwin.hPrevInstance = hPrevInstance;
311         textwin.nCmdShow = nCmdShow;
312         textwin.Title = "gnuplot";
313
314         get_user_env(); /* this hasn't been called yet */
315         textwin.IniFile = gp_strdup("~\\wgnuplot.ini");
316         gp_expand_tilde(&(textwin.IniFile));
317
318         /* if tilde expansion fails use current directory as
319            default - that was the previous default behaviour */
320         if (textwin.IniFile[0] == '~') {
321             free(textwin.IniFile);
322             textwin.IniFile = "wgnuplot.ini";
323         }
324         textwin.IniSection = "WGNUPLOT";
325         textwin.DragPre = "load '";
326         textwin.DragPost = "'\n";
327         textwin.lpmw = &menuwin;
328         textwin.ScreenSize.x = 80;
329         textwin.ScreenSize.y = 80;
330         textwin.KeyBufSize = 2048;
331         textwin.CursorFlag = 1; /* scroll to cursor after \n & \r */
332         textwin.shutdown = MakeProcInstance((FARPROC)ShutDown, hInstance);
333         textwin.AboutText = (LPSTR)farmalloc(1024);
334         CheckMemory(textwin.AboutText);
335         sprintf(textwin.AboutText,"Version %s\nPatchlevel %s\nLast Modified %s\n%s\n%s, %s and many others",
336                 gnuplot_version, gnuplot_patchlevel, gnuplot_date, gnuplot_copyright, authors[1], authors[0]);
337         textwin.AboutText = (LPSTR)farrealloc(textwin.AboutText, _fstrlen(textwin.AboutText)+1);
338         CheckMemory(textwin.AboutText);
339
340         menuwin.szMenuName = szMenuName;
341
342         pausewin.hInstance = hInstance;
343         pausewin.hPrevInstance = hPrevInstance;
344         pausewin.Title = "gnuplot pause";
345
346         graphwin.hInstance = hInstance;
347         graphwin.hPrevInstance = hPrevInstance;
348         graphwin.Title = "gnuplot graph";
349         graphwin.lptw = &textwin;
350         graphwin.IniFile = textwin.IniFile;
351         graphwin.IniSection = textwin.IniSection;
352         graphwin.color=TRUE;
353         graphwin.fontsize = WINFONTSIZE;
354
355         if (TextInit(&textwin))
356                 exit(1);
357         textwin.hIcon = LoadIcon(hInstance, "TEXTICON");
358 #ifdef WIN32
359         SetClassLong(textwin.hWndParent, GCL_HICON, (DWORD)textwin.hIcon);
360 #else
361         SetClassWord(textwin.hWndParent, GCW_HICON, (WORD)textwin.hIcon);
362 #endif
363         if (_argc>1) {
364                 int i,noend=FALSE;
365                 for (i=0; i<_argc; ++i)
366                         if (!stricmp(_argv[i],"-noend") || !stricmp(_argv[i],"/noend")
367                             || !stricmp(_argv[i],"-persist"))
368                                 noend = TRUE;
369                 if (noend)
370                         ShowWindow(textwin.hWndParent, textwin.nCmdShow);
371         }
372         else
373                 ShowWindow(textwin.hWndParent, textwin.nCmdShow);
374         if (IsIconic(textwin.hWndParent)) { /* update icon */
375                 RECT rect;
376                 GetClientRect(textwin.hWndParent, (LPRECT) &rect);
377                 InvalidateRect(textwin.hWndParent, (LPRECT) &rect, 1);
378                 UpdateWindow(textwin.hWndParent);
379         }
380
381
382         atexit(WinExit);
383
384         gnu_main(_argc, _argv, environ);
385
386         return 0;
387 }
388
389
390 /* replacement stdio routines that use Text Window for stdin/stdout */
391 /* WARNING: Do not write to stdout/stderr with functions not listed
392    in win/wtext.h */
393
394 #undef kbhit
395 #undef getche
396 #undef getch
397 #undef putch
398
399 #undef fgetc
400 #undef getchar
401 #undef getc
402 #undef fgets
403 #undef gets
404
405 #undef fputc
406 #undef putchar
407 #undef putc
408 #undef fputs
409 #undef puts
410
411 #undef fprintf
412 #undef printf
413 #undef vprintf
414 #undef vfprintf
415
416 #undef fwrite
417 #undef fread
418
419 #if defined(__MSC__)|| defined(WIN32)
420 #define isterm(f) (f==stdin || f==stdout || f==stderr)
421 #else
422 #define isterm(f) isatty(fileno(f))
423 #endif
424
425 int
426 MyPutCh(int ch)
427 {
428     return TextPutCh(&textwin, (BYTE)ch);
429 }
430
431 int
432 MyKBHit()
433 {
434     return TextKBHit(&textwin);
435 }
436
437 int
438 MyGetCh()
439 {
440     return TextGetCh(&textwin);
441 }
442
443 int
444 MyGetChE()
445 {
446     return TextGetChE(&textwin);
447 }
448
449 int
450 MyFGetC(FILE *file)
451 {
452     if (isterm(file)) {
453         return MyGetChE();
454     }
455     return fgetc(file);
456 }
457
458 char *
459 MyGetS(char *str)
460 {
461     TextPutS(&textwin,"\nDANGER: gets() used\n");
462     MyFGetS(str,80,stdin);
463     if (strlen(str) > 0
464         && str[strlen(str)-1]=='\n')
465         str[strlen(str)-1] = '\0';
466     return str;
467 }
468
469 char *
470 MyFGetS(char *str, unsigned int size, FILE *file)
471 {
472     char FAR *p;
473
474     if (isterm(file)) {
475         p = TextGetS(&textwin, str, size);
476         if (p != (char FAR *)NULL)
477             return str;
478         return (char *)NULL;
479     }
480     return fgets(str,size,file);
481 }
482
483 int
484 MyFPutC(int ch, FILE *file)
485 {
486     if (isterm(file)) {
487         MyPutCh((BYTE)ch);
488         TextMessage();
489         return ch;
490     }
491     return fputc(ch,file);
492 }
493
494 int
495 MyFPutS(const char *str, FILE *file)
496 {
497     if (isterm(file)) {
498         TextPutS(&textwin, (char*) str);
499         TextMessage();
500         return (*str);  /* different from Borland library */
501     }
502     return fputs(str,file);
503 }
504
505 int
506 MyPutS(char *str)
507 {
508     TextPutS(&textwin, str);
509     MyPutCh('\n');
510     TextMessage();
511     return 0;   /* different from Borland library */
512 }
513
514 int
515 MyFPrintF(FILE *file, const char *fmt, ...)
516 {
517     int count;
518     va_list args;
519
520     va_start(args,fmt);
521     if (isterm(file)) {
522         char buf[MAXPRINTF];
523
524         count = vsprintf(buf,fmt,args);
525         TextPutS(&textwin,&buf[0]);
526     } else
527         count = vfprintf(file, fmt, args);
528     va_end(args);
529     return count;
530 }
531
532 int
533 MyVFPrintF(FILE *file, const char *fmt, va_list args)
534 {
535     int count;
536
537     if (isterm(file)) {
538         char buf[MAXPRINTF];
539         count = vsprintf(buf,fmt,args);
540         TextPutS(&textwin, buf);
541     } else
542         count = vfprintf(file, fmt, args);
543     return count;
544 }
545
546 int
547 MyPrintF(const char *fmt, ...)
548 {
549     int count;
550     char buf[MAXPRINTF];
551     va_list args;
552
553     va_start(args,fmt);
554     count = vsprintf(buf,fmt,args);
555     TextPutS(&textwin,buf);
556     va_end(args);
557     return count;
558 }
559
560 size_t
561 MyFWrite(const void *ptr, size_t size, size_t n, FILE *file)
562 {
563     if (isterm(file)) {
564         size_t i;
565         for (i=0; i<n; i++)
566             TextPutCh(&textwin, ((BYTE *)ptr)[i]);
567         TextMessage();
568         return n;
569     }
570     return fwrite(ptr, size, n, file);
571 }
572
573 size_t
574 MyFRead(void *ptr, size_t size, size_t n, FILE *file)
575 {
576     if (isterm(file)) {
577         size_t i;
578
579         for (i=0; i<n; i++)
580             ((BYTE *)ptr)[i] = TextGetChE(&textwin);
581         TextMessage();
582         return n;
583     }
584     return fread(ptr, size, n, file);
585 }
586
587 /* public interface to printer routines : Windows PRN emulation
588  * (formerly in win.trm)
589  */
590
591 #define MAX_PRT_LEN 256
592 static char win_prntmp[MAX_PRT_LEN+1];
593
594 FILE *
595 open_printer()
596 {
597     char *temp;
598
599     if ((temp = getenv("TEMP")) == (char *)NULL)
600         *win_prntmp='\0';
601     else  {
602         strncpy(win_prntmp,temp,MAX_PRT_LEN);
603         /* stop X's in path being converted by mktemp */
604         for (temp=win_prntmp; *temp; temp++)
605             *temp = tolower(*temp);
606         if ( strlen(win_prntmp) && (win_prntmp[strlen(win_prntmp)-1]!='\\') )
607             strcat(win_prntmp,"\\");
608     }
609     strncat(win_prntmp, "_gptmp",MAX_PRT_LEN-strlen(win_prntmp));
610     strncat(win_prntmp, "XXXXXX",MAX_PRT_LEN-strlen(win_prntmp));
611     mktemp(win_prntmp);
612     return fopen(win_prntmp, "w");
613 }
614
615 void
616 close_printer(FILE *outfile)
617 {
618     fclose(outfile);
619     DumpPrinter(graphwin.hWndGraph, graphwin.Title, win_prntmp);
620 }
621
622 void
623 screen_dump()
624 {
625     GraphPrint(&graphwin);
626 }
627
628 void
629 win_raise_terminal_window()
630 {
631     ShowWindow(graphwin.hWndGraph, SW_SHOWNORMAL);
632     BringWindowToTop(graphwin.hWndGraph);
633 }
634
635 void
636 win_lower_terminal_window()
637 {
638     SetWindowPos(graphwin.hWndGraph, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
639 }
640