1 /* windClient.c -
2  *
3  *	Send button pushes and commands to the window's command
4  *	interpreters.
5  *
6  *     *********************************************************************
7  *     * Copyright (C) 1985, 1990 Regents of the University of California. *
8  *     * Permission to use, copy, modify, and distribute this              *
9  *     * software and its documentation for any purpose and without        *
10  *     * fee is hereby granted, provided that the above copyright          *
11  *     * notice appear in all copies.  The University of California        *
12  *     * makes no representations about the suitability of this            *
13  *     * software for any purpose.  It is provided "as is" without         *
14  *     * express or implied warranty.  Export of this software outside     *
15  *     * of the United States of America may require an export license.    *
16  *     *********************************************************************
17  */
18 
19 #ifndef lint
20 static char rcsid[] __attribute__ ((unused)) ="$Header: /usr/cvsroot/magic-8.0/windows/windClient.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
21 #endif  /* not lint */
22 
23 #include <stdio.h>
24 
25 #include "utils/magic.h"
26 #include "textio/textio.h"
27 #include "utils/geometry.h"
28 #include "windows/windows.h"
29 #include "graphics/glyphs.h"
30 #include "windows/windInt.h"
31 #include "tiles/tile.h"
32 #include "utils/hash.h"
33 #include "database/database.h"
34 #include "utils/main.h"
35 #include "utils/macros.h"
36 #include "utils/utils.h"
37 #include "utils/malloc.h"
38 #include "graphics/graphics.h"
39 #include "utils/styles.h"
40 #include "textio/txcommands.h"
41 #include "utils/undo.h"
42 
43 /* The following defines are used to indicate corner positions
44  * of the box:
45  */
46 
47 #define WIND_BL 0
48 #define WIND_BR 1
49 #define WIND_TR 2
50 #define WIND_TL 3
51 #define WIND_ILG -1
52 
53 /* our window client ID */
54 global WindClient windClientID = (WindClient) NULL;
55 
56 extern int windBorderCmd();
57 extern int windCaptionCmd(), windCrashCmd(), windCursorCmd();
58 extern int windFilesCmd(), windCloseCmd(), windOpenCmd();
59 extern int windQuitCmd(), windRedrawCmd();
60 extern int windResetCmd(), windSpecialOpenCmd();
61 extern int windOverCmd(), windUnderCmd(), windDebugCmd();
62 extern int windDumpCmd(), windHelpCmd();
63 extern int windMacroCmd(), windIntMacroCmd();
64 extern int windLogCommandsCmd(), windUpdateCmd(), windSleepCmd();
65 extern int windSetpointCmd();
66 extern int windPushbuttonCmd();
67 extern int windPauseCmd(), windGrstatsCmd();
68 extern int windGrowCmd();
69 extern int windUndoCmd(), windRedoCmd();
70 extern int windCenterCmd(), windScrollCmd();
71 extern int windVersionCmd(), windViewCmd(), windXviewCmd(), windZoomCmd();
72 extern int windScrollBarsCmd(), windPositionsCmd();
73 extern int windNamesCmd();
74 
75 
76 #ifdef MAGIC_WRAPPER
77 extern int windBypassCmd();
78 #else
79 extern int windEchoCmd(), windSourceCmd(), windSendCmd();
80 #endif
81 
82 static Rect windFrameRect;
83 static MagWindow *windFrameWindow;
84 static int windButton = TX_LEFT_BUTTON;
85 static int windCorner = WIND_ILG;	/* Nearest corner when button went
86 					 * down.
87 					 */
88 
89 
90 /*
91  * ----------------------------------------------------------------------------
92  *	windButtonSetCursor --
93  *
94  * 	Used to set the programmable cursor for a particular
95  *	button state.
96  *
97  * Results:
98  *	None.
99  *
100  * Side effects:
101  *	Selects and sets a programmable cursor based on the given
102  *	button (for sizing or moving) and corner.
103  * ----------------------------------------------------------------------------
104  */
105 
106 void
windButtonSetCursor(button,corner)107 windButtonSetCursor(button, corner)
108     int button;			/* Button that is down. */
109     int corner;			/* Corner to be displayed in cursor. */
110 {
111     switch (corner)
112     {
113 	case WIND_BL:
114 	    if (button == TX_LEFT_BUTTON)
115 		GrSetCursor(STYLE_CURS_LLWIND);
116 	    else
117 		GrSetCursor(STYLE_CURS_LLWINDCORN);
118 	    break;
119 	case WIND_BR:
120 	    if (button == TX_LEFT_BUTTON)
121 		GrSetCursor(STYLE_CURS_LRWIND);
122 	    else
123 		GrSetCursor(STYLE_CURS_LRWINDCORN);
124 	    break;
125 	case WIND_TL:
126 	    if (button == TX_LEFT_BUTTON)
127 		GrSetCursor(STYLE_CURS_ULWIND);
128 	    else
129 		GrSetCursor(STYLE_CURS_ULWINDCORN);
130 	    break;
131 	case WIND_TR:
132 	    if (button == TX_LEFT_BUTTON)
133 		GrSetCursor(STYLE_CURS_URWIND);
134 	    else
135 		GrSetCursor(STYLE_CURS_URWINDCORN);
136 	    break;
137     }
138 }
139 
140 
141 /*
142  * ----------------------------------------------------------------------------
143  * windGetCorner --
144  *
145  * 	Returns the corner of the window closest to a given screen location.
146  *
147  * Results:
148  *	An integer value is returned, indicating the corner closest to
149  *	the given screen location.
150  *
151  * Side effects:
152  *	None.
153  * ----------------------------------------------------------------------------
154  */
155 
156 int
windGetCorner(screenPoint,screenRect)157 windGetCorner(screenPoint, screenRect)
158     Point *screenPoint;
159     Rect *screenRect;
160 
161 {
162     Rect r;
163 
164     /* Find out which corner is closest.  Consider only the
165      * intersection of the box with the window (otherwise it
166      * may not be possible to select off-screen corners.
167      */
168 
169     r = *screenRect;
170     GeoClip(&r, &GrScreenRect);
171     if (screenPoint->p_x < ((r.r_xbot + r.r_xtop)/2))
172     {
173 	if (screenPoint->p_y < ((r.r_ybot + r.r_ytop)/2))
174 	    return WIND_BL;
175 	else
176 	    return WIND_TL;
177     }
178     else
179     {
180 	if (screenPoint->p_y < ((r.r_ybot + r.r_ytop)/2))
181 	    return WIND_BR;
182 	else
183 	    return WIND_TR;
184     }
185 }
186 
187 /*
188  * ----------------------------------------------------------------------------
189  * windMoveRect --
190  *
191  * 	Repositions a rectangle by one of its corners.
192  *
193  * Results:
194  *	None.
195  *
196  * Side effects:
197  *	The rectangle is changed so that the given corner is at the
198  *	given position.
199  * ----------------------------------------------------------------------------
200  */
201 
202 void
windMoveRect(wholeRect,corner,p,rect)203 windMoveRect(wholeRect, corner, p, rect)
204     bool wholeRect;		/* move the whole thing?  or just a corner? */
205     int corner;			/* Specifies a corner in the format
206 				 * returned by ToolGetCorner.
207 				 */
208     Point *p;			/* New position of corner, in screen
209 				 * coordinates.
210 				 */
211     Rect *rect;
212 {
213     int x, y, tmp;
214 
215     /* Move the rect.  If an illegal corner is specified, then
216      * move by the bottom-left corner.
217      */
218 
219     if (wholeRect)
220     {
221 	switch (corner)
222 	{
223 	    case WIND_BL:
224 		x = p->p_x - rect->r_xbot;
225 		y = p->p_y - rect->r_ybot;
226 		break;
227 	    case WIND_BR:
228 		x = p->p_x - rect->r_xtop;
229 		y = p->p_y - rect->r_ybot;
230 		break;
231 	    case WIND_TR:
232 		x = p->p_x - rect->r_xtop;
233 		y = p->p_y - rect->r_ytop;
234 		break;
235 	    case WIND_TL:
236 		x = p->p_x - rect->r_xbot;
237 		y = p->p_y - rect->r_ytop;
238 		break;
239 	    default:
240 		x = p->p_x - rect->r_xbot;
241 		y = p->p_y - rect->r_ybot;
242 		break;
243 	}
244 	rect->r_xbot += x;
245 	rect->r_ybot += y;
246 	rect->r_xtop += x;
247 	rect->r_ytop += y;
248     }
249     else
250     {
251 	switch (corner)
252 	{
253 	    case WIND_BL:
254 		rect->r_xbot = p->p_x;
255 		rect->r_ybot = p->p_y;
256 		break;
257 	    case WIND_BR:
258 		rect->r_xtop = p->p_x;
259 		rect->r_ybot = p->p_y;
260 		break;
261 	    case WIND_TR:
262 		rect->r_xtop = p->p_x;
263 		rect->r_ytop = p->p_y;
264 		break;
265 	    case WIND_TL:
266 		rect->r_xbot = p->p_x;
267 		rect->r_ytop = p->p_y;
268 		break;
269 	}
270 
271 	/* If the movement turned the box inside out, turn it right
272 	 * side out again.
273 	 */
274 
275 	if (rect->r_xbot > rect->r_xtop)
276 	{
277 	    tmp = rect->r_xtop;
278 	    rect->r_xtop = rect->r_xbot;
279 	    rect->r_xbot = tmp;
280 	}
281 	if (rect->r_ybot > rect->r_ytop)
282 	{
283 	    tmp = rect->r_ytop;
284 	    rect->r_ytop = rect->r_ybot;
285 	    rect->r_ybot = tmp;
286 	}
287 
288     }
289 }
290 
291 
292 /*
293  * ----------------------------------------------------------------------------
294  * Button Routines --
295  *
296  * 	This page contains a set of routines to handle the puck
297  *	buttons within the window border.
298  *
299  * Results:
300  *	None.
301  *
302  * Side effects:
303  *	Left button:  used to move the whole window by the lower-left corner.
304  *	Right button: used to re-size the window by its upper-right corner.
305  *		If one of the left or right buttons is pushed, then the
306  *		other is pushed, the corner is switched to the nearest
307  *		one to the cursor.  This corner is remembered for use
308  *		in box positioning/sizing when both buttons have gone up.
309  *	Bottom button: Center the view on the point where the crosshair is
310  *		at when the button is released.
311  * ----------------------------------------------------------------------------
312  */
313 
314 void
windFrameDown(w,cmd)315 windFrameDown(w, cmd)
316     MagWindow *w;
317     TxCommand *cmd;
318 {
319     if (WindOldButtons == 0)
320     {
321 	windFrameRect = w->w_frameArea;
322 	windFrameWindow = w;
323 	windButton = cmd->tx_button;
324     }
325 #define BOTHBUTTONS (TX_LEFT_BUTTON | TX_RIGHT_BUTTON)
326     if ((WindNewButtons & BOTHBUTTONS) == BOTHBUTTONS)
327     {
328 	windCorner = windGetCorner(&(cmd->tx_p), &(windFrameWindow->w_frameArea));
329     }
330     else if (cmd->tx_button == TX_LEFT_BUTTON)
331     {
332 	windCorner = WIND_BL;
333 	windButtonSetCursor(windButton, windCorner);
334     }
335     else if (cmd->tx_button == TX_RIGHT_BUTTON)
336     {
337 	windCorner = WIND_TR;
338 	windButtonSetCursor(windButton, windCorner);
339     }
340 }
341 
342     /*ARGSUSED*/
343 void
windFrameUp(w,cmd)344 windFrameUp(w, cmd)
345     MagWindow *w;
346     TxCommand *cmd;
347 {
348     if (WindNewButtons == 0)
349     {
350 	GrSetCursor(STYLE_CURS_NORMAL);
351 	switch (cmd->tx_button)
352 	{
353 	    case TX_LEFT_BUTTON:
354 	    case TX_RIGHT_BUTTON:
355 		windMoveRect( (windButton == TX_LEFT_BUTTON),
356 			windCorner, &(cmd->tx_p), &windFrameRect);
357 		WindReframe(windFrameWindow, &windFrameRect, FALSE,
358 			(windButton == TX_LEFT_BUTTON) );
359 		break;
360 	}
361     }
362     else
363     {
364 	/* If both buttons are down and one is released, we just change
365 	 * the cursor to reflect the current corner and the remaining
366 	 * button (i.e. move or size window).
367 	 */
368 
369 	windCorner = windGetCorner(&(cmd->tx_p), &(windFrameWindow->w_frameArea));
370 	windButtonSetCursor(windButton, windCorner);
371     }
372 }
373 
374 /*
375  * ----------------------------------------------------------------------------
376  * windFrameButtons --
377  *
378  *	Handle button pushes to the window frame area (zoom and scroll)
379  *	Always handle scroll bars ourselves, even if there is an external
380  *	window package.  BUT---in the Tcl/Tk version of Magic, the
381  *	window does not set WIND_SCROLLBARS, causing this routine to be
382  *	bypassed.
383  *
384  * Results:
385  *	TRUE if the button was pushed in the frame and handled by one
386  *	of the button handler routines, FALSE if not.
387  *
388  * Side effects:
389  *	Depends upon where the button was pushed.
390  * ----------------------------------------------------------------------------
391  */
392 
393 bool
windFrameButtons(w,cmd)394 windFrameButtons(w, cmd)
395     MagWindow *w;
396     TxCommand *cmd;
397 {
398     extern void windBarLocations();
399 
400     Rect leftBar, botBar, up, down, right, left, zoom;
401     Point p;
402 
403     if (w == NULL) return FALSE;
404     p.p_x = w->w_screenArea.r_xtop - w->w_screenArea.r_xbot;
405     p.p_y = w->w_screenArea.r_ytop - w->w_screenArea.r_ybot;
406 
407     if ((w->w_flags & WIND_SCROLLBARS) != 0)
408     {
409 	windBarLocations(w, &leftBar, &botBar, &up, &down, &right, &left, &zoom);
410 	if (cmd->tx_button == TX_MIDDLE_BUTTON) {
411 	    if (GEO_ENCLOSE(&cmd->tx_p, &leftBar))
412 	    {
413 		/* move elevator */
414 		p.p_x = 0;
415 		p.p_y = w->w_bbox->r_ybot +
416 			((w->w_bbox->r_ytop - w->w_bbox->r_ybot) *
417 			(cmd->tx_p.p_y - leftBar.r_ybot))
418 			/ (leftBar.r_ytop - leftBar.r_ybot) -
419 			(w->w_surfaceArea.r_ytop + w->w_surfaceArea.r_ybot)/2;
420 		WindScroll(w, &p, (Point *) NULL);
421 		return TRUE;
422 	    }
423 	    else if (GEO_ENCLOSE(&cmd->tx_p, &botBar))
424 	    {
425 		/* move elevator */
426 		p.p_y = 0;
427 		p.p_x = w->w_bbox->r_xbot +
428 			((w->w_bbox->r_xtop - w->w_bbox->r_xbot) *
429 			(cmd->tx_p.p_x - botBar.r_xbot))
430 			/ (botBar.r_xtop - botBar.r_xbot) -
431 			(w->w_surfaceArea.r_xtop + w->w_surfaceArea.r_xbot)/2;
432 		WindScroll(w, &p, (Point *) NULL);
433 		return TRUE;
434 	    }
435 	    else if (GEO_ENCLOSE(&cmd->tx_p, &up))
436 	    {
437 		/* scroll up */
438 		p.p_y = -p.p_y;
439 		p.p_x = 0;
440 		WindScroll(w, (Point *) NULL, &p);
441 		return TRUE;
442 	    }
443 	    else if (GEO_ENCLOSE(&cmd->tx_p, &down))
444 	    {
445 		/* scroll down */
446 		p.p_x = 0;
447 		WindScroll(w, (Point *) NULL, &p);
448 		return TRUE;
449 	    }
450 	    else if (GEO_ENCLOSE(&cmd->tx_p, &right))
451 	    {
452 		/* scroll right */
453 		p.p_x = -p.p_x;
454 		p.p_y = 0;
455 		WindScroll(w, (Point *) NULL, &p);
456 		return TRUE;
457 	    }
458 	    else if (GEO_ENCLOSE(&cmd->tx_p, &left))
459 	    {
460 		/* scroll left */
461 		p.p_y = 0;
462 		WindScroll(w, (Point *) NULL, &p);
463 		return TRUE;
464 	    }
465 	}
466 	if (GEO_ENCLOSE(&cmd->tx_p, &zoom)) {
467 	    /* zoom in, out, or view */
468 	    switch (cmd->tx_button)
469 	    {
470 		case TX_LEFT_BUTTON:
471 		    WindZoom(w, 2.0);
472 		    break;
473 		case TX_MIDDLE_BUTTON:
474 		    WindView(w);
475 		    break;
476 		case TX_RIGHT_BUTTON:
477 		    WindZoom(w, 0.5);
478 		    break;
479 	    }
480 	    return TRUE;
481 	}
482     }
483     return FALSE;
484 }
485 
486 /*
487  * ----------------------------------------------------------------------------
488  * windClientButtons --
489  *
490  *	Handle button pushes to the window border.
491  *
492  * Results:
493  *	None.
494  *
495  * Side effects:
496  *	depends upon where the button was pushed.
497  * ----------------------------------------------------------------------------
498  */
499 
500 void
windClientButtons(w,cmd)501 windClientButtons(w, cmd)
502     MagWindow *w;
503     TxCommand *cmd;
504 {
505     /*
506      * Is this an initial 'down push' in a non-iconic window?  If so, we
507      * will initiate some user-interaction sequence, such as moving the corner
508      * of the window or growing it to full-screen size.
509      *
510      * (An 'iconic' window is one that is closed down to an icon -- this
511      * currently only happens when we are using the Sun window package, but
512      * in the future it might happen in other cases too.)
513      *
514      */
515 
516     if ((WindOldButtons == 0) && ((w->w_flags & WIND_ISICONIC) == 0))
517     {
518 	/* single button down */
519 	Point p;
520 	Rect caption;
521 
522 	windFrameWindow = NULL;
523 	if (w == NULL) return;
524 	p.p_x = w->w_screenArea.r_xtop - w->w_screenArea.r_xbot;
525 	p.p_y = w->w_screenArea.r_ytop - w->w_screenArea.r_ybot;
526 	caption = w->w_allArea;
527 	if ((w->w_flags & WIND_CAPTION) != 0)
528 	    caption.r_ybot = caption.r_ytop - TOP_BORDER(w) + 1;
529 	else
530 	    caption.r_ybot = caption.r_ytop;
531 
532 	/* Handle 'grow' for our window package. */
533 	if (WindPackageType == WIND_MAGIC_WINDOWS)
534 	{
535 	    if ((cmd->tx_button == TX_MIDDLE_BUTTON) &&
536 				GEO_ENCLOSE(&cmd->tx_p, &caption))
537 	    {
538 		WindFullScreen(w);
539 		return;
540 	    }
541 	}
542 	if (windFrameButtons(w, cmd)) return;
543 
544 	/* Otherwise, continue onward */
545     }
546 
547     /*
548      * At this point, we have decided that the button was not an initial
549      * button push for Magic's window package.  Maybe an external window
550      * package wants it, or maybe it is a continuation of a previous Magic
551      * sequence (such as moving a corner of a window).
552      */
553     switch ( WindPackageType )
554     {
555 	case WIND_X_WINDOWS:
556 	    break;
557 
558 	default:
559 	    /* Magic Windows */
560 	    if (cmd->tx_button == TX_MIDDLE_BUTTON)
561 		return;
562 	    if ((cmd->tx_buttonAction == TX_BUTTON_UP) &&
563 		(windFrameWindow == NULL))
564 		return;
565 
566 	    /* no special area or else an up push -- reframe window */
567 	    switch (cmd->tx_buttonAction)
568 	    {
569 		case TX_BUTTON_DOWN:
570 		    windFrameDown(w, cmd);
571 		    break;
572 		case TX_BUTTON_UP:
573 		    windFrameUp(w, cmd);
574 		    break;
575 		default:
576 		    TxError("windClientButtons() failed!\n");
577 		    break;
578 	    }
579     }
580 }
581 
582 /*
583  * ----------------------------------------------------------------------------
584  * WindButtonInFrame --
585  *
586  *	To be called from the graphics packages. Handle button pushes to
587  *	the window frame area (zoom and scroll) by calling windFrameButtons()
588  *	if it appears to be appropriate for this MagWindow structure.
589  *	This bypasses the key macro handler, thus hard-coding the button
590  *	actions for the frame.
591  *
592  * Results:
593  *	TRUE if the button was pushed in the frame and handled by one
594  *	of the button handler routines, FALSE if not.
595  *
596  * Side effects:
597  *	Depends upon where the button was pushed.
598  * ----------------------------------------------------------------------------
599  */
600 
601 bool
WindButtonInFrame(w,x,y,b)602 WindButtonInFrame(w, x, y, b)
603     MagWindow *w;
604     int x;
605     int y;
606     int b;
607 {
608     TxCommand cmd;
609     cmd.tx_p.p_x = x;
610     cmd.tx_p.p_y = y;
611     cmd.tx_button = b;
612     if (windFrameButtons(w, &cmd))
613     {
614 	WindUpdate();
615 	return TRUE;
616     }
617     return FALSE;
618 }
619 
620 
621 /*
622  * ----------------------------------------------------------------------------
623  *
624  * windClientInterp
625  *
626  * Window's command interpreter.
627  * Dispatches to long commands, providing them with the window and command
628  * we are passed.
629  *
630  * Results:
631  *	none.
632  *
633  * Side effects:
634  *	Whatever occur as a result of executing the long
635  *	command supplied.
636  *
637  * ----------------------------------------------------------------------------
638  */
639 
640 void
windCmdInterp(w,cmd)641 windCmdInterp(w, cmd)
642     MagWindow *w;
643     TxCommand *cmd;
644 {
645     int cmdNum;
646 
647     switch (cmd->tx_button)
648     {
649         case TX_LEFT_BUTTON:
650         case TX_RIGHT_BUTTON:
651         case TX_MIDDLE_BUTTON:
652 	    windClientButtons(w, cmd);
653 	    break;
654 	case TX_NO_BUTTON:
655 	    if (WindExecute(w, windClientID, cmd) >= 0)
656 		UndoNext();
657 	    break;
658 	default:
659 	    ASSERT(FALSE, "windCmdInterp");
660 	    break;
661     }
662 }
663 
664 
665 /*
666  * ----------------------------------------------------------------------------
667  *  windCmdInit --
668  *
669  *	Initialize the window client.
670  *
671  * Results:
672  *	None.
673  *
674  * Side effects:
675  *	None.
676  * ----------------------------------------------------------------------------
677  */
678 
679 void
windClientInit()680 windClientInit()
681 {
682     windClientID = WindAddClient(WINDOW_CLIENT, ( bool (*)() ) NULL,
683 	( bool (*)() ) NULL, ( void (*)() ) NULL, windCmdInterp,
684 	( void (*)() ) NULL, ( bool (*)() ) NULL, ( void (*)() ) NULL,
685 	(GrGlyph *) NULL);
686 
687     /* Set up all of the window commands */
688 
689 #ifdef MAGIC_WRAPPER
690     WindAddCommand(windClientID,
691 	"*bypass command	run command independently of the command line",
692 	windBypassCmd, FALSE);
693 #endif
694     WindAddCommand(windClientID,
695 	"*crash			cause a core dump",
696 	windCrashCmd, FALSE);
697     WindAddCommand(windClientID,
698 	"*files			print out currently open files",
699 	windFilesCmd, FALSE);
700     WindAddCommand(windClientID,
701 	"*grstats		print out stats on graphics",
702 	windGrstatsCmd, FALSE);
703     WindAddCommand(windClientID,
704 	"*pause	[args]		print args and wait for <cr>",
705 	windPauseCmd, FALSE);
706     WindAddCommand(windClientID,
707 	"*winddebug		set debugging mode",
708 	windDebugCmd, FALSE);
709     WindAddCommand(windClientID,
710 	"*winddump		print out debugging info",
711 	windDumpCmd, FALSE);
712 
713     WindAddCommand(windClientID,
714 	"center [x y]		center window on the cursor or indicated coordinate",
715 	windCenterCmd, FALSE);
716     WindAddCommand(windClientID,
717 	"closewindow [name]	close a window",
718 	windCloseCmd, FALSE);
719     WindAddCommand(windClientID,
720 	"cursor			return magic coordinates of the cursor",
721 	windCursorCmd, FALSE);
722     WindAddCommand(windClientID,
723 	"grow			blow a window up to full-screen size or back again",
724 	windGrowCmd, FALSE);
725     WindAddCommand(windClientID,
726 	"help [pattern]		print out synopses for all commands valid\n\
727 			in the current window (or just those\n\
728 			containing pattern)",
729 	windHelpCmd, FALSE);
730     WindAddCommand(windClientID,
731         "imacro [char [string]] define or print an interactive macro called char",
732         windIntMacroCmd, FALSE);
733     WindAddCommand(windClientID,
734 	"logcommands [file [update]]\n\
735 			log all commands into a file",
736 	windLogCommandsCmd, FALSE);
737     WindAddCommand(windClientID,
738         "macro [char [string]]  define or print a macro called char",
739         windMacroCmd, FALSE);
740     WindAddCommand(windClientID,
741 	"openwindow [cell][name]\n\
742 			open a new window with indicated name, bound to indicated cell",
743 	windOpenCmd, FALSE);
744     WindAddCommand(windClientID,
745 	"over			move a window over (on top of) the rest",
746 	windOverCmd, FALSE);
747     WindAddCommand(windClientID,
748 	"pushbutton button act	push a mouse button",
749 	windPushbuttonCmd, FALSE);
750     WindAddCommand(windClientID,
751 	"redo [count]		redo commands",
752 	windRedoCmd, FALSE);
753     WindAddCommand(windClientID,
754 	"redraw			redraw the display",
755 	windRedrawCmd, FALSE);
756     WindAddCommand(windClientID,
757 	"reset			reset the display",
758 	windResetCmd, FALSE);
759     WindAddCommand(windClientID,
760 	"scroll dir [amount]	scroll the window",
761 	windScrollCmd, FALSE);
762     WindAddCommand(windClientID,
763 	"setpoint [x y [WID]]	force to cursor (point) to x,y in window WID",
764 	windSetpointCmd, FALSE);
765     WindAddCommand(windClientID,
766 	"sleep seconds		sleep for a number of seconds",
767 	windSleepCmd, FALSE);
768     WindAddCommand(windClientID,
769 	"specialopen [coords] type [args]\n\
770 			open a special window",
771 	windSpecialOpenCmd, FALSE);
772     WindAddCommand(windClientID,
773 	"quit			exit magic",
774 	windQuitCmd, FALSE);
775     WindAddCommand(windClientID,
776 	"underneath		move a window underneath the rest",
777 	windUnderCmd, FALSE);
778     WindAddCommand(windClientID,
779 	"undo [count]		undo commands",
780 	windUndoCmd, FALSE);
781     WindAddCommand(windClientID,
782 #ifdef MAGIC_WRAPPER
783 	"updatedisplay [suspend|resume]\n\
784 			force display update, or suspend/resume updates",
785 #else
786 	"updatedisplay		force the display to be updated",
787 #endif
788 	windUpdateCmd, FALSE);
789     WindAddCommand(windClientID,
790 	"version			print out version info",
791 	windVersionCmd, FALSE);
792     WindAddCommand(windClientID,
793 	"view [get]              zoom window out so everything is visible",
794 	windViewCmd, FALSE);
795     WindAddCommand(windClientID,
796 	"windowborder [on|off]	toggle border drawing for new windows",
797 	windBorderCmd, FALSE);
798     WindAddCommand(windClientID,
799 	"windowcaption [on|off]	toggle title caption for new windows",
800 	windCaptionCmd, FALSE);
801     WindAddCommand(windClientID,
802 	"windowscrollbars [on|off]\n\
803 			toggle scroll bars for new windows",
804 	windScrollBarsCmd, FALSE);
805     WindAddCommand(windClientID,
806 	"windowpositions [file]	print out window positions",
807 	windPositionsCmd, FALSE);
808     WindAddCommand(windClientID,
809 	"xview               	zoom window out so everything is unexpanded",
810 	windXviewCmd, FALSE);
811     WindAddCommand(windClientID,
812 	"zoom amount		zoom window by amount",
813 	windZoomCmd, FALSE);
814     WindAddCommand(windClientID,
815 	"windownames [all|type]	get name of current or all windows",
816 	windNamesCmd, FALSE);
817 #ifndef MAGIC_WRAPPER
818     WindAddCommand(windClientID,
819 	"echo [-n] [strings]	print text on the terminal",
820 	windEchoCmd, FALSE);
821     WindAddCommand(windClientID,
822 	"send type command	send a command to a certain window type",
823 	windSendCmd, FALSE);
824     WindAddCommand(windClientID,
825 	"source filename		read in commands from file",
826 	windSourceCmd, FALSE);
827 #endif
828 }
829