1 /* windCmdSZ.c -
2  *
3  *	This file contains Magic command routines for those commands
4  *	that are valid in all windows.
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/windCmdSZ.c,v 1.1.1.1 2008/02/03 20:43:50 tim Exp $";
21 #endif  /* not lint */
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <unistd.h>		/* for sleep() */
26 #include <string.h>
27 #include <math.h>
28 
29 #include "tcltk/tclmagic.h"
30 #include "utils/magic.h"
31 #include "textio/textio.h"
32 #include "utils/geometry.h"
33 #include "tiles/tile.h"
34 #include "windows/windows.h"
35 #include "graphics/glyphs.h"
36 #include "windows/windInt.h"
37 #include "utils/undo.h"
38 #include "utils/utils.h"
39 #include "utils/signals.h"
40 #include "textio/txcommands.h"
41 #include "utils/hash.h"
42 #include "database/database.h"
43 #include "dbwind/dbwind.h"
44 #include "graphics/graphics.h"
45 
46 
47 /*
48  * ----------------------------------------------------------------------------
49  *
50  * windScrollCmd --
51  *
52  *	Scroll the view around
53  *
54  * Usage:
55  *	scroll dir [amount [units]]
56  *
57  * Results:
58  *	None.
59  *
60  * Side effects:
61  *	The window underneath the cursor is changed.
62  *	Note: behavior has been changed from original.  To have "amount"
63  *	parsed as a fractional scroll amount, "units" *must* be declared
64  *	as "w".  Otherwise, no units implies that "amount" is an absolute
65  *	value.
66  *
67  *
68  * ----------------------------------------------------------------------------
69  */
70 
71 void
windScrollCmd(w,cmd)72 windScrollCmd(w, cmd)
73     MagWindow *w;
74     TxCommand *cmd;
75 {
76     Rect r;
77     int xsize, ysize;
78     Point p;
79     int pos, locargc = cmd->tx_argc;
80     float amount;
81     bool doFractional = FALSE;
82 
83     if ( (cmd->tx_argc < 2) || (cmd->tx_argc > 4) )
84     {
85 	TxError("Usage: %s direction [amount [units]]\n", cmd->tx_argv[0]);
86 	return;
87     }
88 
89     if (w == NULL)
90     {
91 	TxError("Point to a window first.\n");
92 	return;
93     }
94 
95     if ((w->w_flags & WIND_SCROLLABLE) == 0) {
96 	TxError("Sorry, can't scroll this window.\n");
97 	return;
98     };
99 
100     pos = GeoNameToPos(cmd->tx_argv[1], FALSE, TRUE);
101     if (pos < 0 || pos == GEO_CENTER)
102 	return;
103 
104     if (cmd->tx_argc == 2)	/* default = half-screen pan */
105     {
106 	r = w->w_screenArea;
107 	amount = 0.5;
108 	doFractional = TRUE;
109     }
110     else if (cmd->tx_argc == 4)
111     {
112 	char unitc = cmd->tx_argv[3][0];
113 
114 	if (unitc == 'w')
115 	    r = w->w_screenArea;
116 	else if (unitc == 'l')
117 	    r = *(w->w_bbox);
118 	else
119 	{
120 	    TxError("Usage: %s direction [amount [units]]\n", cmd->tx_argv[0]);
121 	    TxError("  'units' must be one of 'w' (window) or 'l' (layout);\n");
122 	    return;
123 	}
124 
125 	if (sscanf(cmd->tx_argv[2], "%f", &amount) != 1)
126 	{
127 	    TxError("Usage: %s direction [amount [units]]\n", cmd->tx_argv[0]);
128 	    TxError("  'amount' is a fractional value.\n");
129 	    return;
130 	}
131 	doFractional = TRUE;
132     }
133 
134     if (doFractional)
135     {
136 	xsize = (r.r_xtop - r.r_xbot) * amount;
137 	ysize = (r.r_ytop - r.r_ybot) * amount;
138     }
139     else
140     {
141 	/* Alternate syntax: parse for integer coordinate amount to scroll */
142 	xsize = cmdParseCoord(w, cmd->tx_argv[2], TRUE, TRUE);
143 	ysize = cmdParseCoord(w, cmd->tx_argv[2], TRUE, FALSE);
144     }
145 
146     p.p_x = 0;
147     p.p_y = 0;
148 
149     switch (pos)
150     {
151 	case GEO_NORTH:
152 	    p.p_y = -ysize;
153 	    break;
154 	case GEO_SOUTH:
155 	    p.p_y = ysize;
156 	    break;
157 	case GEO_EAST:
158 	    p.p_x = -xsize;
159 	    break;
160 	case GEO_WEST:
161 	    p.p_x = xsize;
162 	    break;
163 	case GEO_NORTHEAST:
164 	    p.p_x = -xsize;
165 	    p.p_y = -ysize;
166 	    break;
167 	case GEO_NORTHWEST:
168 	    p.p_x = xsize;
169 	    p.p_y = -ysize;
170 	    break;
171 	case GEO_SOUTHEAST:
172 	    p.p_x = -xsize;
173 	    p.p_y = ysize;
174 	    break;
175 	case GEO_SOUTHWEST:
176 	    p.p_x = xsize;
177 	    p.p_y = ysize;
178 	    break;
179     }
180 
181     if (doFractional)
182 	WindScroll(w, (Point *) NULL, &p);
183     else
184     {
185 	/* Direction is reversed w/respect to above call to WindScroll() */
186 	p.p_x = -p.p_x;
187 	p.p_y = -p.p_y;
188 	WindScroll(w, &p, (Point *) NULL);
189     }
190 
191     return;
192 }
193 
194 /*
195  * ----------------------------------------------------------------------------
196  * windSetpointCmd --
197  *
198  *	Use the x, y specified as the location of the point tool for the
199  *	next command.
200  *
201  * Results:
202  *	None.  Under the Tcl interpreter, returns the screen and layout
203  *	coordinates as a list of four integers: sx sy lx ly.
204  *
205  * Side effects:
206  *	global variables.
207  * ----------------------------------------------------------------------------
208  */
209 
210 void
windSetpointCmd(w,cmd)211 windSetpointCmd(w, cmd)
212     MagWindow *w;
213     TxCommand *cmd;
214 {
215     int wid;
216     Point rootPoint;
217 #ifdef MAGIC_WRAPPER
218     char *ptstr;
219 #endif
220 
221     if ((cmd->tx_argc != 4) && (cmd->tx_argc != 3) && (cmd->tx_argc != 1))
222 	goto usage;
223     if ((cmd->tx_argc != 1) && !
224 	(StrIsInt(cmd->tx_argv[1]) && StrIsInt(cmd->tx_argv[2])) )
225 	goto usage;
226 
227     if (cmd->tx_argc == 4) {
228 	if (StrIsInt(cmd->tx_argv[3]))
229 	   wid = atoi(cmd->tx_argv[3]);
230 	else if (GrWindowIdPtr)
231 	   wid = (*GrWindowIdPtr)(cmd->tx_argv[3]);
232 	else
233 	   wid = WIND_UNKNOWN_WINDOW;
234     }
235     else if (w != NULL)
236 	wid = w->w_wid;
237     else {
238 	windCheckOnlyWindow(&w, DBWclientID);
239 	if (w != NULL)
240 	   wid = w->w_wid;
241 	else
242 	   wid = WIND_UNKNOWN_WINDOW;
243     }
244 
245     /* Ensure a valid window, if possible */
246     if (w == NULL) w = WindSearchWid(wid);
247 
248     if (cmd->tx_argc == 1)
249     {
250 	if (w != (MagWindow *) NULL)
251 	{
252 	    WindPointToSurface(w, &cmd->tx_p, &rootPoint, (Rect *) NULL);
253 
254 #ifdef MAGIC_WRAPPER
255 	    ptstr = (char *)Tcl_Alloc(50);
256 	    sprintf(ptstr, "%d %d %d %d", cmd->tx_p.p_x, cmd->tx_p.p_y,
257 			rootPoint.p_x, rootPoint.p_y);
258 	    Tcl_SetResult(magicinterp, ptstr, TCL_DYNAMIC);
259 #else
260 	    TxPrintf("Point is at screen coordinates (%d, %d) in window %d.\n",
261 			cmd->tx_p.p_x, cmd->tx_p.p_y, w->w_wid);
262 	    TxPrintf("Point is at layout coordinates (%d, %d)\n",
263 			rootPoint.p_x, rootPoint.p_y);
264 #endif
265 	} else {
266 	    TxPrintf("Point is at screen coordinates (%d, %d).\n",
267 			cmd->tx_p.p_x, cmd->tx_p.p_y);
268 	}
269     }
270     else {
271 	int yval;
272 
273 	yval = atoi(cmd->tx_argv[2]);
274 
275 	/* Reinterpret coordinates according to the graphics package */
276 	switch (WindPackageType)
277 	{
278 	    case WIND_X_WINDOWS:
279 		/* Windows have origin at lower-left corner */
280 		yval = w->w_allArea.r_ytop - yval;
281 		break;
282 	}
283 	TxSetPoint(atoi(cmd->tx_argv[1]), yval, wid);
284     }
285     return;
286 
287 usage:
288     TxError("Usage: %s [x y [window ID|name]]\n", cmd->tx_argv[0]);
289 }
290 
291 int
windSetPrintProc(name,val)292 windSetPrintProc(name, val)
293     char *name;
294     char *val;
295 {
296     TxPrintf("%s = \"%s\"\n", name, val);
297     return 0;
298 }
299 
300 
301 /*
302  * ----------------------------------------------------------------------------
303  * windSleepCmd --
304  *
305  *	Take a nap.
306  *
307  * Results:
308  *	None.
309  *
310  * Side effects:
311  *	None.
312  * ----------------------------------------------------------------------------
313  */
314 
315 void
windSleepCmd(w,cmd)316 windSleepCmd(w, cmd)
317     MagWindow *w;
318     TxCommand *cmd;
319 {
320     int time;
321 
322     if (cmd->tx_argc != 2)
323     {
324 	TxError("Usage: %s seconds\n", cmd->tx_argv[0]);
325 	return;
326     }
327 
328     time = atoi(cmd->tx_argv[1]);
329     for ( ; time > 1; time--)
330     {
331 	sleep(1);
332 	if (SigInterruptPending) return;
333     }
334 }
335 
336 #ifndef MAGIC_WRAPPER
337 
338 
339 /*
340  * ----------------------------------------------------------------------------
341  *
342  * windSourceCmd --
343  *
344  * Implement the "source" command.
345  * Process a file as a list of commands.
346  *
347  * Usage:
348  *	source filename
349  *
350  * Results:
351  *	None.
352  *
353  * Side effects:
354  *	Whatever the commands request.
355  *
356  * ----------------------------------------------------------------------------
357  */
358 
359 void
windSourceCmd(w,cmd)360 windSourceCmd(w, cmd)
361     MagWindow *w;
362     TxCommand *cmd;
363 {
364     FILE *f;
365 
366     if (cmd->tx_argc != 2)
367     {
368 	TxError("Usage: %s filename\n", cmd->tx_argv[0]);
369 	return;
370     }
371 
372     f = PaOpen(cmd->tx_argv[1], "r", (char *) NULL, ".",
373 	    SysLibPath, (char **) NULL);
374     if (f == NULL)
375 	TxError("Couldn't read from %s.\n", cmd->tx_argv[1]);
376     else {
377 	TxDispatch(f);
378 	(void) fclose(f);
379     };
380 }
381 
382 #endif
383 
384 /*
385  * ----------------------------------------------------------------------------
386  * windSpecialOpenCmd --
387  *
388  *	Open a new window at the cursor position.  Give it a default size,
389  *	and take the client's name from the command line.  Pass the rest of
390  *	the command arguments off to the client.
391  *
392  * Results:
393  *	None.
394  *
395  * Side effects:
396  *	None.
397  * ----------------------------------------------------------------------------
398  */
399 
400 void
windSpecialOpenCmd(w,cmd)401 windSpecialOpenCmd(w, cmd)
402     MagWindow *w;
403     TxCommand *cmd;
404 {
405     WindClient wc;
406     Rect area;
407     bool haveCoords;
408     char *client;
409 
410     haveCoords = FALSE;
411 
412     if (cmd->tx_argc < 2) goto usage;
413     haveCoords = StrIsInt(cmd->tx_argv[1]);
414     if (haveCoords && (
415 	(cmd->tx_argc < 6) ||
416 	!StrIsInt(cmd->tx_argv[2]) ||
417 	!StrIsInt(cmd->tx_argv[3]) ||
418 	!StrIsInt(cmd->tx_argv[4])
419 	)) goto usage;
420     if (haveCoords)
421 	client = cmd->tx_argv[5];
422     else
423 	client = cmd->tx_argv[1];
424 
425     wc = WindGetClient(client, FALSE);
426     /* clients whose names begin with '*' are hidden */
427     if ((wc == (WindClient) NULL) || (client[0] == '*')) goto usage;
428 
429     if (haveCoords) {
430 	windCheckOnlyWindow(&w, wc);
431 
432 	area.r_xbot = atoi(cmd->tx_argv[1]);
433 	area.r_ybot = atoi(cmd->tx_argv[2]);
434 	area.r_xtop = MAX(atoi(cmd->tx_argv[3]), area.r_xbot + WIND_MIN_WIDTH);
435 	area.r_ytop = MAX(atoi(cmd->tx_argv[4]), area.r_ybot + WIND_MIN_HEIGHT);
436 	/* Assume that the client will print an error message if it fails */
437 	(void) WindCreate(wc, &area, FALSE, cmd->tx_argc - 6, cmd->tx_argv + 6);
438     }
439     else {
440 	area.r_xbot = cmd->tx_p.p_x - CREATE_WIDTH/2;
441 	area.r_xtop = cmd->tx_p.p_x + CREATE_WIDTH/2;
442 	area.r_ybot = cmd->tx_p.p_y - CREATE_HEIGHT/2;
443 	area.r_ytop = cmd->tx_p.p_y + CREATE_HEIGHT/2;
444 	/* Assume that the client will print an error message if it fails */
445 	(void) WindCreate(wc, &area, TRUE, cmd->tx_argc - 2, cmd->tx_argv + 2);
446     }
447 
448     return;
449 
450 usage:
451     TxPrintf("Usage: specialopen [leftx bottomy rightx topy] type [args]\n");
452     TxPrintf("Valid window types are:\n");
453     WindPrintClientList(FALSE);
454     return;
455 }
456 
457 /*
458  * ----------------------------------------------------------------------------
459  *  windNamesCmd --
460  *
461  *	Register or retrieve the name associated with the layout window
462  *
463  * Results:
464  *	Returns the name as a Tcl string result.  If "all" is selected,
465  *	or if w is NULL and cannot be determined, returns a list of all
466  *	window names.  The first argument may also be a window client
467  *	type, in which case only windows of that type are returned.
468  *
469  * Note:
470  *	This routine can easily be made "generic", not Tcl-specific.
471  *	However, of the graphics interfaces available, only Tcl/Tk keeps
472  *	track of windows by name.
473  *
474  * ----------------------------------------------------------------------------
475  */
476 
477 void
windNamesCmd(w,cmd)478 windNamesCmd(w, cmd)
479     MagWindow *w;
480     TxCommand *cmd;
481 {
482     bool doforall = FALSE;
483     WindClient wc = (WindClient)NULL;
484     MagWindow *sw;
485 
486     if (cmd->tx_argc > 2)
487     {
488 	TxError("Usage:  windownames [all | client_type]\n");
489 	return;
490     }
491     if (cmd->tx_argc == 2)
492     {
493 	if (!strncmp(cmd->tx_argv[1], "all", 3))
494 	    doforall = TRUE;
495 #ifndef THREE_D
496 	else if (!strncmp(cmd->tx_argv[1], "wind3d", 6))
497 	{
498 	    return;	// do nothing
499 	}
500 #endif 	/* THREE_D */
501 	else
502 	{
503 	    wc = WindGetClient(cmd->tx_argv[1], FALSE);
504 	    if (wc == (WindClient) NULL)
505 	    {
506 		TxError("Usage:  windownames [all | client_type]\n");
507 		TxPrintf("Valid window types are:\n");
508 		WindPrintClientList(FALSE);
509 		return;
510 	    }
511 	    doforall = TRUE;
512 	}
513     }
514 
515     if (cmd->tx_argc == 1)
516     {
517 	wc = DBWclientID;
518 	windCheckOnlyWindow(&w, wc);
519 	if (w == (MagWindow *)NULL)
520 	    doforall = TRUE;
521     }
522 
523 #ifdef MAGIC_WRAPPER
524     if (doforall == TRUE)
525     {
526 	Tcl_Obj *tlist;
527 
528 	tlist = Tcl_NewListObj(0, NULL);
529 	for (sw = windTopWindow; sw != NULL; sw = sw->w_nextWindow)
530 	    if ((wc == NULL) || (sw->w_client == wc))
531 	    {
532 		if (GrWindowNamePtr)
533 		    Tcl_ListObjAppendElement(magicinterp, tlist,
534 				Tcl_NewStringObj((*GrWindowNamePtr)(sw), -1));
535 		else
536 		    Tcl_ListObjAppendElement(magicinterp, tlist,
537 				Tcl_NewIntObj(sw->w_wid));
538 	    }
539 	Tcl_SetObjResult(magicinterp, tlist);
540     }
541     else
542     {
543 	if (GrWindowNamePtr)
544 	    Tcl_SetResult(magicinterp, (*GrWindowNamePtr)(w), NULL);
545 	else
546 	    Tcl_SetObjResult(magicinterp, Tcl_NewIntObj(w->w_wid));
547     }
548 #else
549     if (doforall == TRUE)
550     {
551 	if (GrWindowNamePtr)
552 	    TxPrintf("Window ID	Window Name\n");
553 	else
554 	    TxPrintf("Window ID\n");
555 	for (sw = windTopWindow; sw != NULL; sw = sw->w_nextWindow)
556 	    if ((wc == (WindClient)NULL) || (sw->w_client == wc))
557 	    {
558 		if (GrWindowNamePtr)
559 		    TxPrintf("%d    	%s\n", sw->w_wid, (*GrWindowNamePtr)(sw));
560 		else
561 		    TxPrintf("%d\n", sw->w_wid);
562 	    }
563     }
564     else
565     {
566 	if (GrWindowNamePtr)
567 	    TxPrintf("Window ID = %d, Name = %s\n", w->w_wid,
568 			(*GrWindowNamePtr)(w));
569 	else
570 	    TxPrintf("Window ID = %d\n", w->w_wid);
571     }
572 #endif /* !MAGIC_WRAPPER */
573 }
574 
575 
576 /*
577  * ----------------------------------------------------------------------------
578  * windUnderCmd --
579  *
580  *	Move a window underneath the other windows.
581  *
582  * Results:
583  *	None.
584  *
585  * Side effects:
586  *	Screen updates.
587  * ----------------------------------------------------------------------------
588  */
589 
590 void
windUnderCmd(w,cmd)591 windUnderCmd(w, cmd)
592     MagWindow *w;
593     TxCommand *cmd;
594 {
595     if (cmd->tx_argc != 1)
596     {
597 	TxError("Usage: %s\n", cmd->tx_argv[0]);
598     }
599     if (w == NULL)
600     {
601 	TxError("Point to a window first.\n");
602 	return;
603     }
604     WindUnder(w);
605 }
606 
607 
608 /*
609  * ----------------------------------------------------------------------------
610  *
611  * windUndoCmd
612  *
613  * Implement the "undo" command.
614  *
615  * Usage:
616  *	undo [count]
617  *
618  * If a count is supplied, the last count events are undone.  The default
619  * count if none is given is 1.
620  *
621  * Results:
622  *	None.
623  *
624  * Side effects:
625  *	Calls the undo module.
626  *
627  * ----------------------------------------------------------------------------
628  */
629 
630 void
windUndoCmd(w,cmd)631 windUndoCmd(w, cmd)
632     MagWindow *w;
633     TxCommand *cmd;
634 {
635     int count;
636 
637     if (cmd->tx_argc > 3)
638     {
639 	TxError("Usage: undo [count]\n");
640 	TxError("       undo print [count]\n");
641 	TxError("       undo enable|disable\n");
642 	return;
643     }
644     else if (cmd->tx_argc == 3)
645     {
646 	if (strncmp(cmd->tx_argv[1], "print", 5))
647 	{
648 	    TxError("Usage: undo print count\n");
649 	    return;
650 	}
651 	else if (!StrIsInt(cmd->tx_argv[2]))
652 	{
653 	    TxError("Usage: undo print count\n");
654 	    return;
655 	}
656 	else
657 	{
658 	    /* Implement undo stack trace */
659 	    UndoStackTrace((-1) - atoi(cmd->tx_argv[2]));
660 	    return;
661 	}
662     }
663     else if (cmd->tx_argc == 2)
664     {
665 	if (!StrIsInt(cmd->tx_argv[1]))
666 	{
667 	    if (!strcmp(cmd->tx_argv[1], "enable"))
668 		UndoEnable();
669 	    else if (!strcmp(cmd->tx_argv[1], "disable"))
670 		UndoDisable();
671 	    else
672 		TxError("Option must be a count (integer)\n");
673 	    return;
674 	}
675 	count = atoi(cmd->tx_argv[1]);
676 	if (count < 0)
677 	{
678 	    TxError("Count must be a positive integer\n");
679 	    return;
680 	}
681     }
682     else
683 	count = 1;
684 
685     if (count == 0)
686     {
687 	UndoEnable();
688     }
689     else
690     {
691 	if (UndoBackward(count) == 0)
692 	    TxPrintf("Nothing more to undo\n");
693     }
694 }
695 
696 
697 /*
698  * ----------------------------------------------------------------------------
699  * windUpdateCmd --
700  *
701  *	Force an update of the graphics screen.  This is usually only called
702  *	from command scripts.
703  *
704  * Results:
705  *	None.
706  *
707  * Side effects:
708  *	Display updates.
709  * ----------------------------------------------------------------------------
710  */
711 
712 void
windUpdateCmd(w,cmd)713 windUpdateCmd(w, cmd)
714     MagWindow *w;
715     TxCommand *cmd;
716 {
717     if (cmd->tx_argc == 1)
718 	WindUpdate();
719 #ifdef MAGIC_WRAPPER
720     else if (cmd->tx_argc > 2)
721 	goto badusage;
722     else if (!strcmp(cmd->tx_argv[1], "suspend"))
723 	GrDisplayStatus = DISPLAY_SUSPEND;
724     else if (!strcmp(cmd->tx_argv[1], "resume"))
725 	GrDisplayStatus = DISPLAY_IDLE;
726     else
727 	goto badusage;
728 #else
729     else if (cmd->tx_argc >= 2)
730 	goto badusage;
731 #endif
732     return;
733 
734 badusage:
735     TxError("Usage: %s [suspend | resume]\n", cmd->tx_argv[0]);
736     return;
737 }
738 
739 /*
740  * ----------------------------------------------------------------------------
741  *
742  * windVersionCmd --
743  *
744  *	Print version information.
745  *
746  * Usage:
747  *	version
748  *
749  * Results:
750  *	None.
751  *
752  * Side effects:
753  *	Prints on stdout.
754  *
755  * ----------------------------------------------------------------------------
756  */
757 
758 void
windVersionCmd(w,cmd)759 windVersionCmd(w, cmd)
760     MagWindow *w;
761     TxCommand *cmd;
762 {
763     if (cmd->tx_argc != 1) {
764 	TxError("Usage: %s\n", cmd->tx_argv[0]);
765 	return;
766     }
767 
768     TxPrintf("Version %s revision %s.  Compiled on %s.\n",
769 		MagicVersion, MagicRevision, MagicCompileTime);
770 }
771 
772 /*
773  * ----------------------------------------------------------------------------
774  *
775  * windViewCmd --
776  *
777  * Implement the "View" command.
778  * Change the view in the selected window so everything is visible.
779  *
780  * Usage:
781  *	view
782  *
783  * Results:
784  *	None.
785  *
786  * Side effects:
787  *	The window underneath the cursor is changed.
788  *	In Tcl version, if supplied with the argument "get", the
789  *	interpreter return value is set to the current view position.
790  *
791  * ----------------------------------------------------------------------------
792  */
793 
794 void
windViewCmd(w,cmd)795 windViewCmd(w, cmd)
796     MagWindow *w;
797     TxCommand *cmd;
798 {
799     if (w == NULL)
800 	return;
801 
802     if (cmd->tx_argc == 1)
803     {
804 	if ((w->w_flags & WIND_SCROLLABLE) == 0) {
805 	    TxError("Sorry, can't zoom out this window.\n");
806 	    return;
807 	}
808 	WindView(w);
809     }
810     else if (cmd->tx_argc == 2)
811     {
812 #ifdef MAGIC_WRAPPER
813 	Tcl_Obj *listxy, *fval;
814 
815 	listxy = Tcl_NewListObj(0, NULL);
816 #endif
817 
818 	if (!strncmp(cmd->tx_argv[1], "get", 3))
819 	{
820 #ifndef MAGIC_WRAPPER
821 	    TxPrintf("(%d, %d) to (%d, %d)\n",
822 			w->w_surfaceArea.r_xbot, w->w_surfaceArea.r_ybot,
823 			w->w_surfaceArea.r_xtop, w->w_surfaceArea.r_ytop);
824 #else
825 	    Tcl_ListObjAppendElement(magicinterp, listxy,
826 			Tcl_NewIntObj((int)w->w_surfaceArea.r_xbot));
827 	    Tcl_ListObjAppendElement(magicinterp, listxy,
828 			Tcl_NewIntObj((int)w->w_surfaceArea.r_ybot));
829 	    Tcl_ListObjAppendElement(magicinterp, listxy,
830 			Tcl_NewIntObj((int)w->w_surfaceArea.r_xtop));
831 	    Tcl_ListObjAppendElement(magicinterp, listxy,
832 			Tcl_NewIntObj((int)w->w_surfaceArea.r_ytop));
833 	    Tcl_SetObjResult(magicinterp, listxy);
834 #endif
835 	}
836 	else if (!strncmp(cmd->tx_argv[1], "bbox", 4))
837 	{
838 #ifndef MAGIC_WRAPPER
839 	    TxPrintf("(%d, %d) to (%d, %d)\n",
840 			w->w_bbox->r_xbot, w->w_bbox->r_ybot,
841 			w->w_bbox->r_xtop, w->w_bbox->r_ytop);
842 #else
843 	    Tcl_ListObjAppendElement(magicinterp, listxy,
844 			Tcl_NewIntObj((int)w->w_bbox->r_xbot));
845 	    Tcl_ListObjAppendElement(magicinterp, listxy,
846 			Tcl_NewIntObj((int)w->w_bbox->r_ybot));
847 	    Tcl_ListObjAppendElement(magicinterp, listxy,
848 			Tcl_NewIntObj((int)w->w_bbox->r_xtop));
849 	    Tcl_ListObjAppendElement(magicinterp, listxy,
850 			Tcl_NewIntObj((int)w->w_bbox->r_ytop));
851 	    Tcl_SetObjResult(magicinterp, listxy);
852 #endif
853 	}
854 	else
855 	{
856 	    char *sptr, *pptr;
857 	    Rect r;
858 
859 	    // Parse out coordinates where all coordinates have been
860 	    // put into a single string argument, as happens when the
861 	    // coordinates are a Tcl list, e.g., from "[box values]"
862 
863 	    sptr = cmd->tx_argv[1];
864 	    if ((pptr = strchr(sptr, ' ')) == NULL) return;
865 	    *pptr++ = '\0';
866 	    r.r_xbot = cmdParseCoord(w, sptr, FALSE, TRUE);
867 
868 	    sptr = pptr;
869 	    if ((pptr = strchr(sptr, ' ')) == NULL) return;
870 	    *pptr++ = '\0';
871 	    r.r_ybot = cmdParseCoord(w, sptr, FALSE, TRUE);
872 
873 	    sptr = pptr;
874 	    if ((pptr = strchr(sptr, ' ')) == NULL) return;
875 	    *pptr++ = '\0';
876 	    r.r_xtop = cmdParseCoord(w, sptr, FALSE, TRUE);
877 	    r.r_ytop = cmdParseCoord(w, pptr, FALSE, TRUE);
878 
879 	    /* Redisplay */
880 	    WindMove(w, &r);
881 	}
882     }
883     else if (cmd->tx_argc == 5)
884     {
885 	Rect r;
886 	r.r_xbot = cmdParseCoord(w, cmd->tx_argv[1], FALSE, TRUE);
887         r.r_ybot = cmdParseCoord(w, cmd->tx_argv[2], FALSE, FALSE);
888         r.r_xtop = cmdParseCoord(w, cmd->tx_argv[3], FALSE, TRUE);
889         r.r_ytop = cmdParseCoord(w, cmd->tx_argv[4], FALSE, FALSE);
890 
891 	/* Redisplay */
892 	WindMove(w, &r);
893     }
894     else
895     {
896 	TxError("Usage: view [get|bbox|llx lly urx ury]\n");
897     }
898 }
899 
900 
901 /*
902  * ----------------------------------------------------------------------------
903  *
904  * windXviewCmd --
905  *
906  * Implement the "Xview" command.
907  * Change the view in the selected window so everything is visible, but
908  * not expanded.
909  *
910  * Usage:
911  *	xview
912  *
913  * Results:
914  *	None.
915  *
916  * Side effects:
917  *	The window underneath the cursor is changed. The root cell of the
918  *	window is unexpanded.
919  *
920  * ----------------------------------------------------------------------------
921  */
922 
923 void
windXviewCmd(w,cmd)924 windXviewCmd(w, cmd)
925     MagWindow *w;
926     TxCommand *cmd;
927 {
928     CellUse *celluse;
929     int ViewUnexpandFunc();
930 
931     if (w == NULL)
932 	return;
933 
934     if ((w->w_flags & WIND_SCROLLABLE) == 0) {
935 	TxError("Sorry, can't zoom out this window.\n");
936 	return;
937     };
938 
939     celluse = (CellUse *) (w->w_surfaceID);
940     DBExpandAll(celluse, &(celluse->cu_bbox),
941 	((DBWclientRec *)w->w_clientData)->dbw_bitmask, FALSE,
942 	ViewUnexpandFunc,
943 	(ClientData)(pointertype) (((DBWclientRec *)w->w_clientData)->dbw_bitmask));
944 
945     WindView(w);
946 }
947 
948 /* This function is called for each cell whose expansion status changed.
949  * It forces the cells area to be redisplayed, then returns 0 to keep
950  * looking for more cells to unexpand.
951  */
952 
953 int
ViewUnexpandFunc(use,windowMask)954 ViewUnexpandFunc(use, windowMask)
955     CellUse *use;		/* Use that was just unexpanded. */
956     int windowMask;		/* Window where it was unexpanded. */
957 {
958     if (use->cu_parent == NULL) return 0;
959     DBWAreaChanged(use->cu_parent, &use->cu_bbox, windowMask,
960 	    (TileTypeBitMask *) NULL);
961     return 0;
962 }
963 
964 
965 /*
966  * ----------------------------------------------------------------------------
967  *
968  * windScrollBarsCmd --
969  *
970  *	Change the flag which says whether new windows will have scroll bars.
971  *
972  * Usage:
973  *	windscrollbars [on|off]
974  *
975  * Results:
976  *	None.
977  *
978  * Side effects:
979  *	A flag is changed.
980  *
981  * ----------------------------------------------------------------------------
982  */
983 
984 void
windScrollBarsCmd(w,cmd)985 windScrollBarsCmd(w, cmd)
986     MagWindow *w;
987     TxCommand *cmd;
988 {
989     int place;
990     static char *onoff[] = {"on", "off", 0};
991     static bool truth[] = {TRUE, FALSE};
992 
993     if (cmd->tx_argc != 2) goto usage;
994 
995     place = Lookup(cmd->tx_argv[1], onoff);
996     if (place < 0) goto usage;
997 
998     if (truth[place])
999     {
1000 	WindDefaultFlags |= WIND_SCROLLBARS;
1001 	TxPrintf("New windows will have scroll bars.\n");
1002     }
1003     else
1004     {
1005 	WindDefaultFlags &= ~WIND_SCROLLBARS;
1006 	TxPrintf("New windows will not have scroll bars.\n");
1007     }
1008     return;
1009 
1010     usage:
1011 	TxError("Usage: %s [on|off]\n", cmd->tx_argv[0]);
1012 	return;
1013 }
1014 
1015 #ifndef MAGIC_WRAPPER
1016 
1017 
1018 /*
1019  * ----------------------------------------------------------------------------
1020  *
1021  * windSendCmd --
1022  *
1023  *	Send a command to a certain window type.  If possible we will pass a
1024  *	arbitrarily chosen window of that type down to the client.
1025  *
1026  * Usage:
1027  *	send type command
1028  *
1029  * Results:
1030  *	None.
1031  *
1032  * Side effects:
1033  *	Whatever the client does
1034  *
1035  * ----------------------------------------------------------------------------
1036  */
1037 
1038 void
windSendCmd(w,cmd)1039 windSendCmd(w, cmd)
1040     MagWindow *w;
1041     TxCommand *cmd;
1042 {
1043     MagWindow *toWindow;
1044     WindClient client;
1045     TxCommand newcmd;
1046     extern int windSendCmdFunc();
1047 
1048     if (cmd->tx_argc < 3) goto usage;
1049     if (cmd->tx_argv[1][0] == '*') goto usage; /* hidden window client */
1050 
1051     client = WindGetClient(cmd->tx_argv[1], FALSE);
1052     if (client == (WindClient) NULL) goto usage;
1053     toWindow = (MagWindow *) NULL;
1054     (void) WindSearch(client, (ClientData) NULL, (Rect *) NULL,
1055 	windSendCmdFunc, (ClientData) &toWindow);
1056     {
1057 	int i;
1058 	newcmd = *cmd;
1059 	newcmd.tx_argc -= 2;
1060 	for (i = 0; i < newcmd.tx_argc; i++) {
1061 	    newcmd.tx_argv[i] = newcmd.tx_argv[i + 2];
1062 	};
1063     }
1064     newcmd.tx_wid = WIND_UNKNOWN_WINDOW;
1065     if (toWindow != NULL) newcmd.tx_wid = toWindow->w_wid;
1066     (void) WindSendCommand(toWindow, &newcmd, FALSE);
1067     return;
1068 
1069     usage:
1070 	TxError("Usage: send type command\n");
1071 	TxPrintf("Valid window types are:\n");
1072 	WindPrintClientList(FALSE);
1073 	return;
1074 }
1075 
1076 int
windSendCmdFunc(w,cd)1077 windSendCmdFunc(w, cd)
1078     MagWindow *w;
1079     ClientData cd;
1080 {
1081     *((MagWindow **) cd) = w;
1082     return 1;
1083 }
1084 
1085 #endif
1086 
1087 /* Structure used by "position" command to pass to WindSearch	*/
1088 /* as client data.						*/
1089 
1090 typedef struct _cdwpos {
1091     FILE *file;
1092     bool doFrame;
1093 } cdwpos;
1094 
1095 
1096 /*
1097  * ----------------------------------------------------------------------------
1098  *
1099  * windPositionsCmd --
1100  *
1101  * Print out the positions of the windows.
1102  *
1103  * Usage:
1104  *	windowpositions [file]
1105  *
1106  * Results:
1107  *	None.
1108  *
1109  * Side effects:
1110  *	A file is written.
1111  *
1112  * ----------------------------------------------------------------------------
1113  */
1114 
1115 void
windPositionsCmd(w,cmd)1116 windPositionsCmd(w, cmd)
1117     MagWindow *w;
1118     TxCommand *cmd;
1119 {
1120     extern int windPositionsFunc();
1121     char *filename = NULL;
1122     cdwpos windpos;
1123 
1124     windpos.doFrame = FALSE;
1125     windpos.file = stdout;
1126 
1127     if (cmd->tx_argc > 3) goto usage;
1128     if (cmd->tx_argc > 1)
1129     {
1130 	if (!strncmp(cmd->tx_argv[1], "frame", 5))
1131 	{
1132 	   windpos.doFrame = TRUE;
1133 	   if (cmd->tx_argc == 3)
1134 		filename = cmd->tx_argv[2];
1135 	}
1136 	else if (cmd->tx_argc == 2)
1137 	   filename = cmd->tx_argv[1];
1138 	else
1139 	    goto usage;
1140     }
1141 
1142     if (filename) {
1143 	windpos.file = fopen(filename, "w");
1144 	if (windpos.file == (FILE *) NULL)
1145 	{
1146 	    TxError("Could not open file %s for writing.\n", filename);
1147 	    return;
1148 	};
1149     }
1150     (void) WindSearch((WindClient) NULL, (ClientData) NULL, (Rect *) NULL,
1151 	windPositionsFunc, (ClientData) &windpos);
1152     if (filename) (void) fclose(windpos.file);
1153     return;
1154 
1155 usage:
1156     TxError("Usage:  windowpositions [file]\n");
1157     return;
1158 }
1159 
1160 int
windPositionsFunc(w,cdata)1161 windPositionsFunc(w, cdata)
1162     MagWindow *w;
1163     ClientData cdata;
1164 {
1165     cdwpos *windpos = (cdwpos *)cdata;
1166     Rect r;
1167 
1168     if (windpos->doFrame)
1169 	r = w->w_frameArea;
1170     else
1171 	r = w->w_screenArea;
1172 
1173     if (windpos->file == stdout)
1174 #ifdef MAGIC_WRAPPER
1175     {
1176 	Tcl_Obj *lobj;
1177 
1178 	lobj = Tcl_NewListObj(0, NULL);
1179 
1180 	Tcl_ListObjAppendElement(magicinterp, lobj, Tcl_NewIntObj((int)r.r_xbot));
1181 	Tcl_ListObjAppendElement(magicinterp, lobj, Tcl_NewIntObj((int)r.r_ybot));
1182 	Tcl_ListObjAppendElement(magicinterp, lobj, Tcl_NewIntObj((int)r.r_xtop));
1183 	Tcl_ListObjAppendElement(magicinterp, lobj, Tcl_NewIntObj((int)r.r_ytop));
1184 	Tcl_ListObjAppendElement(magicinterp, lobj,
1185 		Tcl_NewStringObj(((clientRec *)w->w_client)->w_clientName,
1186 		strlen(((clientRec *)w->w_client)->w_clientName)));
1187 	Tcl_SetObjResult(magicinterp, lobj);
1188     }
1189 #else
1190 	TxPrintf("specialopen %d %d %d %d %s\n",
1191 		r.r_xbot, r.r_ybot, r.r_xtop, r.r_ytop,
1192 		((clientRec *) w->w_client)->w_clientName);
1193 #endif
1194     else
1195 	fprintf((FILE *)cdata, "specialopen %d %d %d %d %s\n",
1196 		r.r_xbot, r.r_ybot, r.r_xtop, r.r_ytop,
1197 		((clientRec *) w->w_client)->w_clientName);
1198     return 0;
1199 }
1200 
1201 
1202 /*
1203  * ----------------------------------------------------------------------------
1204  *
1205  * windZoomCmd --
1206  *
1207  * Implement the "zoom" command.
1208  * Change the view in the selected window by the given scale factor.
1209  *
1210  * Usage:
1211  *	zoom amount
1212  *
1213  * Results:
1214  *	None.
1215  *
1216  * Side effects:
1217  *	The window underneath the cursor is changed.
1218  *
1219  * ----------------------------------------------------------------------------
1220  */
1221 
1222 void
windZoomCmd(w,cmd)1223 windZoomCmd(w, cmd)
1224     MagWindow *w;
1225     TxCommand *cmd;
1226 {
1227     float factor;
1228 
1229     if (w == NULL)
1230 	return;
1231 
1232     if ((w->w_flags & WIND_SCROLLABLE) == 0) {
1233 	TxError("Sorry, can't zoom this window.\n");
1234 	return;
1235     };
1236 
1237     if (cmd->tx_argc != 2)
1238     {
1239 	TxError("Usage: %s factor\n", cmd->tx_argv[0]);
1240 	return;
1241     }
1242 
1243     factor = MagAtof(cmd->tx_argv[1]);
1244     if ((factor <= 0) || (factor >= 20))
1245     {
1246 	TxError("zoom factor must be between 0 and 20.\n");
1247 	return;
1248     }
1249 
1250     WindZoom(w, factor);
1251 }
1252