5 * This file contains the main program for "wish", a windowing
6 * shell based on Tk and Tcl. It also provides a template that
7 * can be used as the basis for main programs for other Tk
10 * Copyright 1990-1992 Regents of the University of California.
11 * Permission to use, copy, modify, and distribute this
12 * software and its documentation for any purpose and without
13 * fee is hereby granted, provided that the above copyright
14 * notice appear in all copies. The University of California
15 * makes no representations about the suitability of this
16 * software for any purpose. It is provided "as is" without
17 * express or implied warranty.
19 * Modifiyed by Peter MacDonald for windows API.
23 static char rcsid
[] = "$Header: /user6/ouster/wish/RCS/main.c,v 1.72 93/02/03 10:20:42 ouster Exp $ SPRITE (Berkeley)";
34 #define dprintf(n,s) dodprintf(s)
36 void dodprintf(char *str
, ... )
48 # include "tclExtend.h"
49 extern Tcl_Interp
*tk_mainInterp
; /* Need to process signals */
53 * Declarations for library procedures:
59 * Command used to initialize wish:
63 static char initCmd
[] = "load wishx.tcl";
65 static char initCmd
[] = "source $tk_library/wish.tcl";
69 * Global variables used by the main program:
72 static Tk_Window w
; /* The main window for the application. If
73 * NULL then the application no longer
75 static Tcl_Interp
*interp
; /* Interpreter for this application. */
76 static int x
, y
; /* Coordinates of last location moved to;
77 * used by "moveto" and "lineto" commands. */
78 static Tcl_CmdBuf buffer
; /* Used to assemble lines of terminal input
79 * into Tcl commands. */
80 static int tty
; /* Non-zero means standard input is a
81 * terminal-like device. Zero means it's
85 * Command-line options:
89 char *fileName
= NULL
;
92 char *geometry
= NULL
;
94 Tk_ArgvInfo argTable
[] = {
95 {"-file", TK_ARGV_STRING
, (char *) NULL
, (char *) &fileName
,
96 "File from which to read commands"},
97 {"-geometry", TK_ARGV_STRING
, (char *) NULL
, (char *) &geometry
,
98 "Initial geometry for window"},
99 {"-display", TK_ARGV_STRING
, (char *) NULL
, (char *) &display
,
101 {"-name", TK_ARGV_STRING
, (char *) NULL
, (char *) &name
,
102 "Name to use for application"},
103 {"-sync", TK_ARGV_CONSTANT
, (char *) 1, (char *) &synchronize
,
104 "Use synchronous mode for display server"},
105 {(char *) NULL
, TK_ARGV_END
, (char *) NULL
, (char *) NULL
,
110 * Declaration for Tcl command procedure to create demo widget. This
111 * procedure is only invoked if SQUARE_DEMO is defined.
114 extern int Tk_SquareCmd
_ANSI_ARGS_((ClientData clientData
,
115 Tcl_Interp
*interp
, int argc
, char **argv
));
118 * Forward declarations for procedures defined later in this file:
121 static void DelayedMap
_ANSI_ARGS_((ClientData clientData
));
122 static int LinetoCmd
_ANSI_ARGS_((ClientData clientData
,
123 Tcl_Interp
*interp
, int argc
, char **argv
));
124 static int MovetoCmd
_ANSI_ARGS_((ClientData clientData
,
125 Tcl_Interp
*interp
, int argc
, char **argv
));
126 static void StdinProc
_ANSI_ARGS_((ClientData clientData
,
128 static void StructureProc
_ANSI_ARGS_((ClientData clientData
,
130 static int _WinCallBack
_ANSI_ARGS_((ClientData clientData
,
131 Tcl_Interp
*interp
, int argc
, char **argv
));
132 static int _getStrHandle
_ANSI_ARGS_((ClientData clientData
,
133 Tcl_Interp
*interp
, int argc
, char **argv
));
137 *----------------------------------------------------------------------
141 * Main program for Wish.
144 * None. This procedure never returns (it exits the process when
148 * This procedure initializes the wish world and then starts
149 * interpreting commands; almost anything could happen, depending
150 * on the script being interpreted.
152 *----------------------------------------------------------------------
156 main( int argc
, /* Number of arguments. */
157 char **argv
) /* Array of argument strings. */
159 char *args
, *p
, *msg
;
160 char buf
[20]; char bigBuf
[300];
165 tk_mainInterp
= interp
= Tcl_CreateExtendedInterp();
167 interp
= Tcl_CreateInterp();
170 Tcl_InitMemory(interp
);
174 * Parse command-line arguments.
178 if (Tk_ParseArgv(interp
, (Tk_Window
) NULL
, &argc
, argv
, argTable
, 0)
180 fprintf(stderr
, "%s\n", interp
->result
);
185 if (fileName
!= NULL
) {
190 name
= strrchr(p
, '/');
199 * Initialize the Tk application and arrange to map the main window
200 * after the startup script has been executed, if any. This way
201 * the script can withdraw the window so it isn't ever mapped
205 w
= Tk_CreateMainWindow(interp
, display
, name
);
207 fprintf(stderr
, "%s\n", interp
->result
);
210 Tk_SetClass(w
, "Tk");
211 Tk_CreateEventHandler(w
, StructureNotifyMask
, StructureProc
,
213 Tk_DoWhenIdle(DelayedMap
, (ClientData
) NULL
);
215 XSynchronize(Tk_Display(w
), True
);
217 Tk_GeometryRequest(w
, 200, 200);
218 border
= Tk_Get3DBorder(interp
, w
, None
, "#ffe4c4");
219 if (border
== NULL
) {
220 Tcl_SetResult(interp
, (char *) NULL
, TCL_STATIC
);
221 Tk_SetWindowBackground(w
, WhitePixelOfScreen(Tk_Screen(w
)));
223 Tk_SetBackgroundFromBorder(w
, border
);
225 XSetForeground(Tk_Display(w
), DefaultGCOfScreen(Tk_Screen(w
)),
226 BlackPixelOfScreen(Tk_Screen(w
)));
229 * Make command-line arguments available in the Tcl variables "argc"
230 * and "argv". Also set the "geometry" variable from the geometry
231 * specified on the command line.
235 args
= Tcl_Merge(argc
-1, argv
+1);
236 Tcl_SetVar(interp
, "argv", args
, TCL_GLOBAL_ONLY
);
238 sprintf(buf
, "%d", argc
-1);
239 Tcl_SetVar(interp
, "argc", buf
, TCL_GLOBAL_ONLY
);
241 if (geometry
!= NULL
) {
242 Tcl_SetVar(interp
, "geometry", geometry
, TCL_GLOBAL_ONLY
);
246 * Add a few application-specific commands to the application's
250 Tcl_CreateCommand(interp
, "lineto", LinetoCmd
, (ClientData
) w
,
252 Tcl_CreateCommand(interp
, "moveto", MovetoCmd
, (ClientData
) w
,
255 Tcl_CreateCommand(interp
, "square", Tk_SquareCmd
, (ClientData
) w
,
258 Tcl_CreateCommand(interp
, "wincallback", _WinCallBack
, (ClientData
) w
,
260 Tcl_CreateCommand(interp
, "getstrhandle", _getStrHandle
, (ClientData
) w
,
264 * Execute Wish's initialization script, followed by the script specified
265 * on the command line, if any.
270 tclAppLongname
= "Wish - Tk Shell";
271 tclAppVersion
= TK_VERSION
;
272 Tcl_ShellEnvInit (interp
, TCLSH_ABORT_STARTUP_ERR
,
274 0, NULL
, /* argv var already set */
275 fileName
== NULL
, /* interactive? */
276 NULL
); /* Standard default file */
278 result
= Tcl_Eval(interp
, initCmd
, 0, (char **) NULL
);
279 if (result
!= TCL_OK
) {
282 strcpy(bigBuf
, Tcl_GetVar(interp
, "auto_path", TCL_GLOBAL_ONLY
));
283 strcat(bigBuf
," /usr/local/windows");
284 Tcl_SetVar(interp
, "auto_path", bigBuf
, TCL_GLOBAL_ONLY
);
285 dprintf(4,("set auto_path \"$auto_path /usr/local/windows\""));
286 if (result
!= TCL_OK
) {
291 if (fileName
!= NULL
) {
292 result
= Tcl_VarEval(interp
, "source ", fileName
, (char *) NULL
);
293 if (result
!= TCL_OK
) {
299 * Commands will come from standard input. Set up a handler
300 * to receive those characters and print a prompt if the input
301 * device is a terminal.
304 Tk_CreateFileHandler(0, TK_READABLE
, StdinProc
, (ClientData
) 0);
311 buffer
= Tcl_CreateCmdBuf();
312 (void) Tcl_Eval(interp
, "update", 0, (char **) NULL
);
315 * Loop infinitely, waiting for commands to execute. When there
316 * are no windows left, Tk_MainLoop returns and we clean up and
319 /* Tcl_Eval( interp, "button .hello -text \"Hello, world\" -command {\n puts stdout \"Hello, world\"; destroy .\n\
320 }\n pack append . .hello {top}\n", 0, (char **)NULL); */
322 Tcl_DeleteInterp(interp
);
323 Tcl_DeleteCmdBuf(buffer
);
327 msg
= Tcl_GetVar(interp
, "errorInfo", TCL_GLOBAL_ONLY
);
329 msg
= interp
->result
;
331 fprintf(stderr
, "%s\n", msg
);
332 Tcl_Eval(interp
, "destroy .", 0, (char **) NULL
);
334 return 0; /* Needed only to prevent compiler warnings. */
338 *----------------------------------------------------------------------
342 * This procedure is invoked by the event dispatcher whenever
343 * standard input becomes readable. It grabs the next line of
344 * input characters, adds them to a command being assembled, and
345 * executes the command if it's complete.
351 * Could be almost arbitrary, depending on the command that's
354 *----------------------------------------------------------------------
359 StdinProc(clientData
, mask
)
360 ClientData clientData
; /* Not used. */
361 int mask
; /* Not used. */
363 #define BUFFER_SIZE 4000
364 char input
[BUFFER_SIZE
+1];
365 static int gotPartial
= 0;
373 Tcl_Eval(interp
, "destroy .", 0, (char **) NULL
);
376 Tk_DeleteFileHandler(0);
385 cmd
= Tcl_AssembleCmd(buffer
, input
);
391 result
= Tcl_RecordAndEval(interp
, cmd
, 0);
392 if (*interp
->result
!= 0) {
393 if ((result
!= TCL_OK
) || (tty
)) {
394 printf("%s\n", interp
->result
);
404 *----------------------------------------------------------------------
408 * This procedure is invoked whenever a structure-related event
409 * occurs on the main window. If the window is deleted, the
410 * procedure modifies "w" to record that fact.
416 * Variable "w" may get set to NULL.
418 *----------------------------------------------------------------------
423 StructureProc(clientData
, eventPtr
)
424 ClientData clientData
; /* Information about window. */
425 XEvent
*eventPtr
; /* Information about event. */
427 if (eventPtr
->type
== DestroyNotify
) {
433 *----------------------------------------------------------------------
437 * This procedure is invoked by the event dispatcher once the
438 * startup script has been processed. It waits for all other
439 * pending idle handlers to be processed (so that all the
440 * geometry information will be correct), then maps the
441 * application's main window.
447 * The main window gets mapped.
449 *----------------------------------------------------------------------
454 DelayedMap(clientData
)
455 ClientData clientData
; /* Not used. */
458 while (Tk_DoOneEvent(TK_IDLE_EVENTS
) != 0) {
459 /* Empty loop body. */
468 *----------------------------------------------------------------------
470 * MoveToCmd and LineToCmd --
472 * This procedures are registered as the command procedures for
473 * "moveto" and "lineto" Tcl commands. They provide a trivial
474 * drawing facility. They don't really work right, in that the
475 * drawn information isn't persistent on the screen (it will go
476 * away if the window is iconified and de-iconified again). The
477 * commands are here partly for testing and partly to illustrate
478 * how to add application-specific commands to Tk. You probably
479 * shouldn't use these commands in any real scripts.
482 * The procedures return standard Tcl results.
485 * The screen gets modified.
487 *----------------------------------------------------------------------
492 MovetoCmd(dummy
, interp
, argc
, argv
)
493 ClientData dummy
; /* Not used. */
494 Tcl_Interp
*interp
; /* Current interpreter. */
495 int argc
; /* Number of arguments. */
496 char **argv
; /* Argument strings. */
499 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
500 " x y\"", (char *) NULL
);
503 x
= strtol(argv
[1], (char **) NULL
, 0);
504 y
= strtol(argv
[2], (char **) NULL
, 0);
509 LinetoCmd(dummy
, interp
, argc
, argv
)
510 ClientData dummy
; /* Not used. */
511 Tcl_Interp
*interp
; /* Current interpreter. */
512 int argc
; /* Number of arguments. */
513 char **argv
; /* Argument strings. */
518 Tcl_AppendResult(interp
, "wrong # args: should be \"", argv
[0],
519 " x y\"", (char *) NULL
);
522 newX
= strtol(argv
[1], (char **) NULL
, 0);
523 newY
= strtol(argv
[2], (char **) NULL
, 0);
524 Tk_MakeWindowExist(w
);
525 XDrawLine(Tk_Display(w
), Tk_WindowId(w
),
526 DefaultGCOfScreen(Tk_Screen(w
)), x
, y
, newX
, newY
);
532 /*===============================================================*/
534 #define _WIN_CODE_SECTION
535 static int dte(char *str
,...);
540 LPWNDCLASS LpWndClass
;
542 static int tclexec(char *str
, ... )
547 vsprintf(buf
,str
,va
);
548 dprintf(32,("tclexec'ing:%s",buf
));
549 result
= Tcl_Eval( interp
, buf
, 0, (char **)NULL
);
551 if (result
!= TCL_OK
)
552 { printf("error evaluating %s\n", buf
);
553 fprintf(stderr
, "%s\n", interp
->result
);
559 static void str2lower(char *str
)
562 { *str
= tolower(*str
);
567 static char *_handles
[300];
568 static int _handInd
=0;
570 static char* getStrHandle(int hndl
)
571 { static char buf
[20];
572 if((hndl
<_handInd
) && (hndl
>=0))
573 return(_handles
[hndl
]);
574 sprintf(buf
, "%d", hndl
);
578 static int findHandle(char* str
)
580 for (i
=0; i
<_handInd
; i
++)
581 if (!strcmp(str
,_handles
[i
]))
586 typedef enum {enum_win
, enum_frame
, enum_canvas
, enum_button
, enum_menu
} class_enum
;
588 static int allocStrHandle(char *seed
, class_enum
class)
590 static char *classes
[]= {"win", "frame", "canvas", "button", "menu"};
591 static int classInds
[10] = { 0, 0, 0, 0, 0, 0};
593 assert((class>=0) && (class<=4));
595 sprintf(buf
,"%s.%s%d", seed
, classes
[class], ++classInds
[class]);
597 sprintf(buf
,"%s%d", classes
[class], ++classInds
[class]);
599 _handles
[_handInd
]=strdup(buf
);
604 static _WinMain(int argc
, char *argv
[])
605 { int i
; char buf
[300];
608 for (i
=1; i
<argc
; i
++)
609 { if (*buf
) strcat(buf
," ");
612 WinMain(getpid(),NULL
,buf
,SW_SHOWNORMAL
); /* or SW_SHOWMINNOACTIVE*/
617 static int _WinCallBack( ClientData clientData
, Tcl_Interp
*interp
,
618 int argc
, char **argv
)
622 { if (!strcmp(argv
[1],"menu"))
625 LpWndClass
->lpfnWndProc(findHandle(argv
[2]),
626 WM_COMMAND
,atoi(argv
[4]),0);
628 CALLWNDPROC(LpWndClass
->lpfnWndProc
,
636 /* for (i=0; i<argc; i++)
637 printf("%s\n", argv[i]);
642 static int _getStrHandle( ClientData clientData
, Tcl_Interp
*interp
,
643 int argc
, char **argv
)
647 { sprintf(interp
->result
, "%s: invalid arg\n", argv
[0]);
651 strcpy(interp
->result
, getStrHandle(i
));
655 _MsMsg2XvMsg(HWND hwnd
, char *event
)
657 WORD message
, wParam
= 0; LONG lParam
= 0;
658 if (1) message
=WM_PAINT
;
660 LpWndClass
->lpfnWndProc(hwnd
,message
,wParam
,lParam
);
662 CALLWNDPROC(LpWndClass
->lpfnWndProc
, hwnd
, message
, wParam
, lParam
);
666 static short *closed_bits
;
668 HWND
CreateWindow(LPSTR szAppName
, LPSTR Label
, DWORD ol
, int x
, int y
, int w
, int h
, HWND d
, HMENU e
, HANDLE i
, LPSTR g
)
671 if (x
== CW_USEDEFAULT
) x
=0;
672 if (y
== CW_USEDEFAULT
) y
=0;
673 if (w
== CW_USEDEFAULT
) w
=500;
674 if (h
== CW_USEDEFAULT
) h
=400;
675 n
=allocStrHandle("",enum_win
);
676 tclexec( "CreateWindow %s \"%s\" %d %d %d %d", getStrHandle(n
), Label
, x
, y
, w
, h
);
681 int DrawText(HDC a
, LPSTR str
, int c
, LPRECT d
, WORD flag
)
682 { int x
=d
->left
, y
=d
->top
, w
= d
->right
, h
=d
->bottom
;
683 if (flag
&DT_SINGLELINE
);
686 if (flag
&DT_VCENTER
);
688 /*tclexec(".%s create text 200 200 -text \"%s\" -anchor n\n",getStrHandle(a), str); */
689 tclexec("DrawText %s \"%s\" %d %d %d %d\n",getStrHandle(a
), str
,
693 BOOL
GetMessage(LPMSG msg
,HWND b
,WORD c
, WORD d
)
694 { static int called
=0;
701 long DispatchMessage(MSG
*msg
)
703 if (tk_NumMainWindows
> 0) {
710 BOOL
TranslateMessage(LPMSG a
){}
712 void MyEventProc( ClientData clientData
, XEvent
*eventPtr
)
717 BOOL
RegisterClass(LPWNDCLASS a
)
719 /* Tk_CreateEventHandler(win,mask,proc,data); */
720 LpWndClass
= a
; return(1);
723 BOOL
ShowWindow(HWND a
, int b
)
725 if (b
!= SW_SHOWNORMAL
)
726 { assert(b
==SW_SHOWMINNOACTIVE
); /* iconize */
731 void UpdateWindow(HWND a
)
735 HDC
BeginPaint(HWND a
, LPPAINTSTRUCT b
)
738 void EndPaint(HWND a
, LPPAINTSTRUCT b
) { }
740 void GetClientRect(HWND a
, LPRECT b
)
741 { b
->top
= 0; b
->left
= 0;
742 b
->bottom
= b
->top
+0;
743 b
->right
= b
->left
+0;
746 HMENU
CreateMenu(void)
747 { static int n
, called
=0;
750 { n
=allocStrHandle("",enum_frame
);
751 tclexec( "CreateMenuBar %s\n",getStrHandle(n
));
754 { n
=allocStrHandle("",enum_menu
);
755 tclexec( "CreateMenuEntry %s any 0\n",getStrHandle(n
));
761 BOOL
AppendMenu(HMENU a
, WORD b
, WORD c
, LPSTR d
)
762 { char *buf
; int dist
,n
;
763 char *cmd
= getStrHandle(a
);
767 if (t
=strchr(buf
,'&'))
768 strcpy(t
,strchr(d
,'&')+1);
771 tclexec("AppendMenu %s %d %s {%s} %d", cmd
, b
, getStrHandle(c
),
776 /* Graphics Primitives */
777 BOOL
Rectangle(HDC a
, int xLeft
, int yTop
, int xRight
, int yBottom
)
779 XDrawRectangle(Tk_Display(w
), Tk_WindowId(w
), DefaultGCOfScreen(Tk_Screen(w
)),
780 xLeft
, yTop
, xRight
-xLeft
+1, yBottom
-yTop
+1);
783 int FillRect(HDC a
,LPRECT b
,HBRUSH c
)
785 XFillRectangle(Tk_Display(w
), Tk_WindowId(w
), DefaultGCOfScreen(Tk_Screen(w
)),
786 b
->left
, b
->top
, b
->right
-b
->left
+1, b
->bottom
-b
->top
+1);
789 static int _LineX
=0, _LineY
=0;
791 int LineTo(HDC a
, int b
, int c
)
793 XDrawLine(Tk_Display(w
), Tk_WindowId(w
), DefaultGCOfScreen(Tk_Screen(w
)),
798 int MoveTo(HDC a
, int b
, int c
) { _LineX
=b
; _LineY
=c
; }
800 BOOL
Arc(HDC a
, int xLeft
, int yTop
, int xRight
, int yBottom
,
801 int xStart
, int yStart
, int xEnd
, int yEnd
)
803 /* XDrawArc(Tk_Display(w), Tk_WindowId(w), DefaultGCOfScreen(Tk_Screen(w)), x,y,..);*/
806 BOOL
Pie(HDC a
, int xLeft
, int yTop
, int xRight
, int yBottom
,
807 int xStart
, int yStart
, int xEnd
, int yEnd
)
811 BOOL
Chord(HDC a
, int xLeft
, int yTop
, int xRight
, int yBottom
,
812 int xStart
, int yStart
, int xEnd
, int yEnd
)
816 static int dte(char *str
,...)
817 { char cmd
[300], *ptr
, *ptr2
;
824 { ptr
= va_arg(va
,char *);
825 ptr2
= va_arg(va
,char *);
826 if (!strncmp("LPSTR",ptr
,5))
827 sprintf(cmd
+strlen(cmd
)," \"%s\"", (ptr2
?ptr2
:""));
828 else if (!strncmp("char",ptr
,4))
829 sprintf(cmd
+strlen(cmd
)," %c\0", ptr2
);
830 else if (!strncmp("HANDLE",ptr
,6))
831 sprintf(cmd
+strlen(cmd
)," %s", getStrHandle((int)ptr2
));
833 sprintf(cmd
+strlen(cmd
)," %d", ptr2
);
840 int wsprintf(LPSTR a
,LPSTR b
,...) {}
842 BOOL
IsCharAlpha(char ch
) { return(isalpha(ch
)); }
843 BOOL
IsCharAlphaNumeric(char ch
) { return(isalnum(ch
)); }
844 BOOL
IsCharUpper(char ch
) { return(isupper(ch
)); }
845 BOOL
IsCharLower(char ch
) { return(islower(ch
)); }
846 int lstrcmp( LPSTR a
, LPSTR b
) { return(strcmp(a
,b
)); }
847 int lstrcmpi( LPSTR a
, LPSTR b
) { return(strcasecmp(a
,b
)); }
848 LPSTR
lstrcpy( LPSTR a
, LPSTR b
) { return(strcpy(a
,b
)); }
849 LPSTR
lstrcat( LPSTR a
, LPSTR b
) { return(strcat(a
,b
)); }
850 int lstrlen( LPSTR a
) { return(strlen(a
)); }
851 int _lopen( LPSTR a
, int b
) { return(open(a
,b
)); }
852 int _lclose( int a
) { return(close(a
)); }
853 int _lcreat( LPSTR a
, int b
) { return(creat(a
,b
)); }
854 LONG
_llseek( int a
, long b
, int c
) { return(lseek(a
,b
,c
)); }
855 WORD
_lread( int a
, LPSTR b
, int c
) { return(read(a
,b
,c
)); }
856 WORD
_lwrite( int a
, LPSTR b
, int c
) { return(write(a
,b
,c
)); }
857 BOOL
ExitWindows(DWORD dwReserved
, WORD wReturnCode
) {exit(0); }