1 /* windMain.c -
2 *
3 * This package implements overlapping windows for the
4 * Magic VLSI layout system.
5 *
6 * Design:
7 * Windows are structures that are kept in a doubly linked list.
8 * Windows near the front of the list are on top of windows further
9 * towards the tail of the list. Each window has some information
10 * about what is in the window, as well as the size of the window
11 * (both unclipped and clipped to accommodate windows that overlay it).
12 * Transforms control what portion of the window's contents show up
13 * on the screen, and at what magnification.
14 *
15 * Each window is owned by a client (the database, a menu package, etc.).
16 * The window package is notified of a new client by the AddClient
17 * call. The client supplies routines to redisplay the contents of
18 * a window, and to do other things with the window (such as delete it).
19 * Each window is a view onto a surface maintained by the client. The
20 * client may be asked to redisplay any part of this surface at any time.
21 * The client must also supply each window with an ID that uniquely
22 * identifies the surface.
23 *
24 * There are currently two types of window packages supported: Magic
25 * windows (implemented here) and Sun Windows. In Magic windows, all
26 * windows use the screen's coordinate system. In Sun Windows, each
27 * window has it's own coordinate system with (0, 0) being at the lower
28 * left corner. Also, under Sun Windows some of the screen managment
29 * stuff (such as clipping to obscuring areas and drawing of the
30 * screen background color) is ignored by us.
31 *
32 *
33 * *********************************************************************
34 * * Copyright (C) 1985, 1990 Regents of the University of California. *
35 * * Permission to use, copy, modify, and distribute this *
36 * * software and its documentation for any purpose and without *
37 * * fee is hereby granted, provided that the above copyright *
38 * * notice appear in all copies. The University of California *
39 * * makes no representations about the suitability of this *
40 * * software for any purpose. It is provided "as is" without *
41 * * express or implied warranty. Export of this software outside *
42 * * of the United States of America may require an export license. *
43 * *********************************************************************
44 */
45
46 #ifndef lint
47 static char rcsid[] __attribute__ ((unused)) = "$Header$";
48 #endif /* not lint */
49
50 #include <stdio.h>
51 #include <string.h>
52 #include <ctype.h> /* for isalnum() */
53
54 #include "utils/magic.h"
55 #include "utils/geometry.h"
56 #include "graphics/glyphs.h"
57 #include "windows/windows.h"
58 #include "windows/windInt.h"
59 #include "utils/stack.h"
60 #include "tiles/tile.h"
61 #include "utils/hash.h"
62 #include "database/database.h"
63 #include "textio/textio.h"
64 #include "graphics/graphics.h"
65 #include "utils/malloc.h"
66 #include "utils/utils.h"
67 #include "textio/txcommands.h"
68
69 /* The type of windows that this package will implement */
70 int WindPackageType = WIND_MAGIC_WINDOWS;
71
72 /* The size of our scroll bars -- may be set externally (see windows.h)
73 */
74 int WindScrollBarWidth = 7;
75
76 /* ------ Internal variables that are global within the window package ----- */
77 clientRec *windFirstClientRec = NULL; /* the head of the linked list
78 * of clients
79 */
80 MagWindow *windTopWindow = NULL; /* the topmost window */
81 MagWindow *windBottomWindow = NULL; /* ...and the bottom window */
82 extern Plane *windRedisplayArea; /* See windDisplay.c for details. */
83
84
85 /*
86 * ----------------------------------------------------------------------------
87 * WindInit --
88 *
89 * Initialize the window package. No windows are created, but the
90 * package will be initialized so that it can do these things in the
91 * future.
92 *
93 * Results:
94 * None.
95 *
96 * Side effects:
97 * Variables internal to the window package are initialized.
98 * ----------------------------------------------------------------------------
99 */
100
101 void
WindInit()102 WindInit()
103 {
104 extern Stack *windGrabberStack;
105 Rect ts;
106 char glyphName[30];
107
108 windClientInit();
109 windGrabberStack = StackNew(2);
110 windRedisplayArea = DBNewPlane((ClientData) TT_SPACE);
111
112 sprintf(glyphName, "windows%d", WindScrollBarWidth);
113 if (!GrReadGlyphs(glyphName, ".", SysLibPath, &windGlyphs))
114 MainExit(1);
115 GrTextSize("XWyqP", GR_TEXT_DEFAULT, &ts);
116 windCaptionPixels = ts.r_ytop - ts.r_ybot + 3;
117 WindAreaChanged((MagWindow *) NULL, (Rect *) NULL);
118 }
119
120
121 /*
122 * ----------------------------------------------------------------------------
123 * WindAddClient --
124 *
125 * Add a new client of the window package. The client must supply a
126 * set of routines, as described below.
127 *
128 * Results:
129 * A unique ID (of type WindClient) is returned.
130 * This is used to identify the client in future calls to the window
131 * package.
132 *
133 * Routines supplied:
134 *
135 * ( A new window was just created for this client. Do things to
136 * initialize the window, such as filling in the caption and making
137 * the contents be empty. The client may refuse to create a new
138 * window by returning FALSE, otherwise the client should return
139 * TRUE. The client will get passed argc and argv, with the command
140 * name stripped off. The client may do whatever it wants with this.
141 * It may even modify parts of the window record -- such as changing
142 * the window's location on the screen.)
143 *
144 * bool
145 * create(w, argc, argv)
146 * MagWindow *w;
147 * int argc;
148 * char *argv[];
149 * {
150 * }
151 *
152 * ( One of the client's windows is about to be deleted. Do whatever
153 * needs to be done, such as freeing up dynamically allocated data
154 * structures. Fields manipulated by the window package, such as
155 * the caption, should not be freed by the client. The client should
156 * normally return TRUE. If the client returns FALSE, the window
157 * manager will refuse the request to delete the window.)
158 *
159 * bool
160 * delete(w)
161 * MagWindow *w;
162 * {
163 * }
164 *
165 * ( Redisplay an area of the screen. The client is passed the window,
166 * the area in his coordinate system, and a clipping rectangle in
167 * screen coordinates. )
168 *
169 * redisplay(w, clientArea, screenArea)
170 * MagWindow *w;
171 * Rect *clientArea, *screenArea;
172 * {
173 * }
174 *
175 *
176 * ( The window is about to be moved or resized. This procedure will
177 * be called twice.
178 *
179 * The first time (with 'final' == FALSE), the window
180 * will be passed in 'w' as it is now and a suggested new w_screenarea
181 * is passed in 'newpos'. The client is free to modify 'newpos' to
182 * be whatever screen location it desires. The routine should not
183 * pass 'w' to any window procedure such as windMove since 'w' has
184 * the old transform, etc. instead of the new one.
185 *
186 * On the second call ('final' == TRUE), the window 'w' has all of
187 * it's fields updated, newpos is equal to w->w_frameArea, and the
188 * client is free to do things like windMove which require a window
189 * as an argument. It should not modify newpos.
190 *
191 * reposition(w, newpos, final)
192 * MagWindow *w;
193 * Rect *newpos -- new w_framearea (screen area of window)
194 * bool final;
195 * {
196 * }
197 *
198 *
199 * ( A command has been issued to this window. The client should
200 * process it. It is split into Unix-style argc and argv words. )
201 *
202 * command(w, client, cmd)
203 * MagWindow *w;
204 * TxCommand *cmd;
205 * {
206 * }
207 *
208 * ( A command has just finished. Update any screen info that may have
209 * been changed as a result. )
210 *
211 * update()
212 * {
213 * }
214 *
215 * Side effects:
216 * Internal tables are expanded to include the new client.
217 * ----------------------------------------------------------------------------
218 */
219
220 WindClient
WindAddClient(clientName,create,delete,redisplay,command,update,exitproc,reposition,icon)221 WindAddClient(clientName, create, delete, redisplay, command, update,
222 exitproc, reposition, icon)
223 char *clientName; /* A textual name for the client. This
224 * name will be visable in the user
225 * interface as the name to use to switch
226 * a window over to a new client
227 */
228 bool (*create)();
229 bool (*delete)();
230 void (*redisplay)();
231 void (*command)();
232 void (*update)();
233 bool (*exitproc)();
234 void (*reposition)();
235 GrGlyph *icon; /* An icon to draw when the window is closed.
236 * (currently for Sun Windows only).
237 */
238 {
239 clientRec *res;
240
241 ASSERT( (clientName != NULL), "WindAddClient");
242 ASSERT( (command != NULL), "WindAddClient");
243
244 res = (clientRec *) mallocMagic(sizeof(clientRec));
245 res->w_clientName = clientName;
246 res->w_create = create;
247 res->w_delete = delete;
248 res->w_redisplay = redisplay;
249 res->w_command = command;
250 res->w_update = update;
251 res->w_exit = exitproc;
252 res->w_reposition = reposition;
253 res->w_icon = icon;
254 res->w_nextClient = windFirstClientRec;
255
256 /* The command and function tables are dynamically allocated. */
257 /* Commands and functions should be registered with the client */
258 /* using the WindAddCommand() function. */
259
260 res->w_commandTable = (char **)mallocMagic(sizeof(char *));
261 *(res->w_commandTable) = NULL;
262 res->w_functionTable = (void (**)())mallocMagic(sizeof(void (*)()));
263 *(res->w_functionTable) = NULL;
264
265 windFirstClientRec = res;
266
267 return (WindClient) res;
268 }
269
270
271 /*
272 * ----------------------------------------------------------------------------
273 * WindGetClient --
274 *
275 * Looks up the unique ID of a client of the window package.
276 *
277 * Results:
278 * A variable of type WindClient is returned if the client was found,
279 * otherwise NULL is returned.
280 *
281 * Side effects:
282 * None.
283 * ----------------------------------------------------------------------------
284 */
285
286 WindClient
WindGetClient(clientName,exact)287 WindGetClient(clientName, exact)
288 char *clientName; /* the textual name of the client */
289 bool exact; /* must the name be exact, or are abbreviations allowed */
290 {
291 clientRec *cr, *found;
292 int length;
293
294 /* Accept only an exact match */
295
296 if (exact)
297 {
298 for (cr = windFirstClientRec; cr != (clientRec *) NULL;
299 cr = cr->w_nextClient)
300 if (!strcmp(clientName, cr->w_clientName))
301 return (WindClient)cr;
302 return (WindClient) NULL;
303 }
304
305 /* Accept any unique abbreviation */
306
307 found = NULL;
308 length = strlen(clientName);
309 for (cr = windFirstClientRec; cr != (clientRec *) NULL;
310 cr = cr->w_nextClient)
311 {
312 if (!strncmp(clientName, cr->w_clientName, length))
313 {
314 if (found != NULL) return (WindClient) NULL;
315 found = cr;
316 }
317 }
318
319 return (WindClient) found;
320 }
321
322 /*
323 * ----------------------------------------------------------------------------
324 * WindNextClient --
325 *
326 * Return the w_nextClient record to the caller as a WindClient
327 * variable. If "client" is 0, pass the first client record.
328 * This allows the calling routine to enumerate all the known
329 * clients.
330 *
331 * Results:
332 * Type WindClient is returned. If the end of the list is
333 * reached, (WindClient)NULL (0) is returned.
334 *
335 * Side effects:
336 * None.
337 * ----------------------------------------------------------------------------
338 */
339
340 WindClient
WindNextClient(client)341 WindNextClient(client)
342 WindClient client;
343 {
344 clientRec *cr = (clientRec *)client;
345 int length;
346
347 if (cr == NULL)
348 return (WindClient)windFirstClientRec;
349 else
350 return (WindClient)(cr->w_nextClient);
351 }
352
353 /*
354 * ----------------------------------------------------------------------------
355 * WindPrintClientList --
356 *
357 * Print the name of each client of the window package.
358 *
359 * Results:
360 * None.
361 *
362 * Side effects:
363 * None.
364 * ----------------------------------------------------------------------------
365 */
366
367 void
WindPrintClientList(wizard)368 WindPrintClientList(wizard)
369 bool wizard; /* If true print the names of ALL clients, even those
370 * that don't have user-visable windows */
371 {
372 clientRec *cr;
373
374 for (cr = windFirstClientRec; cr != (clientRec *) NULL;
375 cr = cr->w_nextClient) {
376 if (wizard || (cr->w_clientName[0] != '*'))
377 TxError(" %s\n", cr->w_clientName);
378 }
379 }
380
381 /*
382 * ----------------------------------------------------------------------------
383 * WindExecute --
384 *
385 * Execute the command associated with a windClient
386 *
387 * Results:
388 * Returns the command index on success. Returns -1 if the
389 * command was not found in the client's command list. Returns
390 * -2 if the procedure was sent an empty command.
391 *
392 * Side effects:
393 * Whatever is done by the command execution.
394 *
395 * ----------------------------------------------------------------------------
396 */
397
398 int
WindExecute(w,rc,cmd)399 WindExecute(w, rc, cmd)
400 MagWindow *w;
401 WindClient rc;
402 TxCommand *cmd;
403 {
404 int cmdNum;
405 clientRec *client = (clientRec *) rc;
406 char **commandTable = client->w_commandTable;
407 void (**functionTable)() = client->w_functionTable;
408
409 if (cmd->tx_argc > 0)
410 {
411 cmdNum = Lookup(cmd->tx_argv[0], commandTable);
412
413 if (cmdNum >= 0)
414 {
415 (*functionTable[cmdNum])(w, cmd);
416 return cmdNum;
417 }
418 return -1;
419 }
420 return -2;
421 }
422
423 /*
424 * ----------------------------------------------------------------------------
425 * WindAddCommand --
426 *
427 * Add a command to the indicated client. The command is passed
428 * in "text", which also contains the (1-line) help text for the
429 * command. "func" is a function pointer, and "volatile" is TRUE
430 * if the command "text" is dynamically allocated and must be
431 * copied before adding to the client.
432 *
433 * Results:
434 * None
435 *
436 * Side effects:
437 * The memory allocated to the command and function pointers may
438 * be reallocated and the entries in the client record updated.
439 *
440 * ----------------------------------------------------------------------------
441 */
442
443 void
WindAddCommand(rc,text,func,dynamic)444 WindAddCommand(rc, text, func, dynamic)
445 WindClient rc;
446 char *text;
447 void (*func)();
448 bool dynamic;
449 {
450 int cidx, numCommands = 0;
451 clientRec *client = (clientRec *) rc;
452 char **commandTable = client->w_commandTable;
453 void (**functionTable)() = client->w_functionTable;
454 char **newcmdTable;
455 void (**newfnTable)();
456
457 /* Find the number of commands and functions, increment by one, and */
458 /* Allocate a new array of pointers. */
459
460 while (commandTable[numCommands] != NULL) numCommands++;
461 numCommands++;
462
463 newcmdTable = (char **)mallocMagic((numCommands + 1) * sizeof(char *));
464 newfnTable = (void (**)())mallocMagic((numCommands + 1) * sizeof(void (*)()));
465
466 /* Copy the old values, inserting the new command in alphabetical */
467 /* order. */
468
469 for (cidx = 0; (commandTable[cidx] != NULL) &&
470 (strcmp(commandTable[cidx], text) < 0); cidx++)
471 {
472 newcmdTable[cidx] = commandTable[cidx];
473 newfnTable[cidx] = functionTable[cidx];
474 }
475
476 if (dynamic)
477 newcmdTable[cidx] = StrDup(NULL, text);
478 else
479 newcmdTable[cidx] = text;
480 newfnTable[cidx] = func;
481
482 for (; commandTable[cidx] != NULL; cidx++)
483 {
484 newcmdTable[cidx + 1] = commandTable[cidx];
485 newfnTable[cidx + 1] = functionTable[cidx];
486 }
487
488 newcmdTable[cidx + 1] = NULL;
489
490 /* Release memory for the original pointers, and replace the */
491 /* pointers in the client record. */
492
493 freeMagic(commandTable);
494 freeMagic(functionTable);
495
496 client->w_commandTable = newcmdTable;
497 client->w_functionTable = newfnTable;
498 }
499
500 /*
501 * ----------------------------------------------------------------------------
502 * WindReplaceCommand --
503 *
504 * Change the function for the indicated command. This routine
505 * is mainly used by the Tcl module interface, where commands
506 * are registered with the command interpreter pointing to an
507 * "auto" function which loads the module, then calls this routine
508 * to replace the auto-load function with the real one.
509 *
510 * Note that this routine matches to the length of "command", then
511 * checks one character beyond in the command table to ensure that
512 * we don't inadvertently change a command which happens to be a
513 * substring of the intended command. In cases where this is
514 * intended (e.g., "ext" and "extract"), the routine must be called
515 * separately for each command string.
516 *
517 * Results:
518 * 0 on success, -1 if the command was not found.
519 *
520 * Side effects:
521 * The clientRec structure for the DBWind interface is altered.
522 *
523 * ----------------------------------------------------------------------------
524 */
525
526 int
WindReplaceCommand(rc,command,newfunc)527 WindReplaceCommand(rc, command, newfunc)
528 WindClient rc;
529 char *command;
530 void (*newfunc)();
531 {
532 int cidx, clen;
533 clientRec *client = (clientRec *) rc;
534 char **commandTable = client->w_commandTable;
535 void (**functionTable)() = client->w_functionTable;
536
537 clen = strlen(command);
538
539 for (cidx = 0; commandTable[cidx] != NULL; cidx++)
540 if (!strncmp(commandTable[cidx], command, clen))
541 if (!isalnum(*(commandTable[cidx] + clen)))
542 {
543 functionTable[cidx] = newfunc;
544 return 0;
545 }
546
547 return -1;
548 }
549
550 /*
551 * ----------------------------------------------------------------------------
552 * WindGetCommandTable --
553 *
554 * For functions wishing to parse the command table of a client
555 * directly, this routine returns a pointer to the top of the
556 * table. The only purpose of this routine is to export the
557 * w_commandTable value inside the clientRec structure, which is
558 * not itself exported.
559 *
560 * Results:
561 * A pointer to the top of the command table of the indicated
562 * client.
563 *
564 * Side effects:
565 * None.
566 * ----------------------------------------------------------------------------
567 */
568
569 char **
WindGetCommandTable(rc)570 WindGetCommandTable(rc)
571 WindClient rc;
572 {
573 clientRec *client = (clientRec *) rc;
574 return client->w_commandTable;
575 }
576