1 #include <stdlib.h>
2 #include "xglk.h"
3 #include "xg_internal.h"
4 #include "xg_win_textbuf.h"
5 #include "xg_win_textgrid.h"
6 #include "xg_win_graphics.h"
7 
8 window_t *gli_rootwin = NULL;
9 window_t *gli_focuswin = NULL;
10 
11 static window_t *gli_windowlist = NULL;
12 
13 /* Window type data structures */
14 
15 typedef struct window_blank_struct {
16   window_t *owner;
17   XRectangle bbox;
18 } window_blank_t;
19 
20 typedef struct window_pair_struct {
21   window_t *child1, *child2;
22   /* split info... */
23   glui32 dir;
24   int vertical, backward;
25   glui32 division;
26   window_t *key; /* NULL or a leaf-descendant (not a Pair) */
27   int keydamage;
28   glui32 size;
29 
30   window_t *owner;
31   XRectangle bbox;
32   int flat; /* true if there's nothing to draw */
33   int splithgt; /* The split center. Will be >= N, < width-N.
34 		   Unless bbox is too small. */
35 
36 } window_pair_t;
37 
38 static window_t *gli_new_window(glui32 type, glui32 rock);
39 static void gli_delete_window(window_t *win);
40 
41 static window_blank_t *win_blank_create(window_t *win);
42 static void win_blank_destroy(window_blank_t *dwin);
43 static void win_blank_rearrange(window_t *win, XRectangle *box);
44 static void win_blank_redraw(window_t *win);
45 
46 static window_pair_t *win_pair_create(window_t *win, glui32 method,
47   window_t *key, glui32 size);
48 static void win_pair_destroy(window_pair_t *dwin);
49 static void win_pair_rearrange(window_t *win, XRectangle *box);
50 static void win_pair_redraw(window_t *win);
51 
init_gli_windows()52 int init_gli_windows()
53 {
54   gli_windowlist = NULL;
55 
56   gli_focuswin = NULL;
57   gli_rootwin = NULL;
58 
59   return TRUE;
60 }
61 
gli_delete_window(window_t * win)62 static void gli_delete_window(window_t *win)
63 {
64   window_t *prev, *next;
65 
66   if (gli_unregister_obj)
67     (*gli_unregister_obj)(win, gidisp_Class_Window, win->disprock);
68 
69   if (win->str) {
70     gli_stream_close(win->str);
71     win->str = NULL;
72   }
73 
74   win->type = -1;
75   win->parent = NULL;
76   win->data = NULL;
77 
78   prev = win->chain_prev;
79   next = win->chain_next;
80   win->chain_prev = NULL;
81   win->chain_next = NULL;
82 
83   if (prev)
84     prev->chain_next = next;
85   else
86     gli_windowlist = next;
87   if (next)
88     next->chain_prev = prev;
89 
90   free(win);
91 }
92 
gli_new_window(glui32 type,glui32 rock)93 static window_t *gli_new_window(glui32 type, glui32 rock)
94 {
95   window_t *win = (window_t *)malloc(sizeof(window_t));
96 
97   if (!win)
98     return NULL;
99 
100   win->type = type;
101 
102   win->rock = rock;
103   win->parent = NULL; /* for now */
104   win->data = NULL; /* for now */
105   win->mouse_request = FALSE;
106   win->char_request = FALSE;
107   win->line_request = FALSE;
108   win->hyperlink_request = FALSE;
109   win->style = 0;
110   win->linkid = 0;
111 
112   win->str = gli_stream_open_window(win);
113   win->echostr = NULL;
114 
115   win->chain_prev = NULL;
116   win->chain_next = gli_windowlist;
117   gli_windowlist = win;
118   if (win->chain_next) {
119     win->chain_next->chain_prev = win;
120   }
121 
122   if (gli_register_obj)
123     win->disprock = (*gli_register_obj)(win, gidisp_Class_Window);
124   else
125     win->disprock.ptr = NULL;
126 
127   return win;
128 }
129 
gli_window_fixiterate(window_t * win)130 window_t *gli_window_fixiterate(window_t *win)
131 {
132   if (!win)
133     return gli_rootwin;
134 
135   if (win->type == wintype_Pair) {
136     window_pair_t *dwin = win->data;
137     if (!dwin->backward)
138       return dwin->child1;
139     else
140       return dwin->child2;
141   }
142   else {
143     window_t *parwin;
144     window_pair_t *dwin;
145 
146     while (win->parent) {
147       parwin = win->parent;
148       dwin = parwin->data;
149       if (!dwin->backward) {
150 	if (win == dwin->child1)
151 	  return dwin->child2;
152       }
153       else {
154 	if (win == dwin->child2)
155 	  return dwin->child1;
156       }
157       win = parwin;
158     }
159 
160     return NULL;
161   }
162 }
163 
glk_window_iterate(window_t * win,glui32 * rock)164 window_t *glk_window_iterate(window_t *win, glui32 *rock)
165 {
166   if (!win) {
167     win = gli_windowlist;
168   }
169   else {
170     win = win->chain_next;
171   }
172 
173   if (win) {
174     if (rock)
175       *rock = win->rock;
176     return win;
177   }
178 
179   if (rock)
180     *rock = 0;
181   return NULL;
182 }
183 
glk_window_get_root()184 winid_t glk_window_get_root()
185 {
186   if (!gli_rootwin)
187     return 0;
188   return gli_rootwin;
189 }
190 
glk_window_get_rock(window_t * win)191 glui32 glk_window_get_rock(window_t *win)
192 {
193   if (!win) {
194     gli_strict_warning("window_get_rock: invalid ref");
195     return 0;
196   }
197   return win->rock;
198 }
199 
glk_window_get_type(window_t * win)200 glui32 glk_window_get_type(window_t *win)
201 {
202   if (!win) {
203     gli_strict_warning("window_get_type: invalid ref");
204     return 0;
205   }
206   return win->type;
207 }
208 
glk_window_get_parent(window_t * win)209 winid_t glk_window_get_parent(window_t *win)
210 {
211   if (!win) {
212     gli_strict_warning("window_get_parent: invalid ref");
213     return 0;
214   }
215   if (win->parent)
216     return win->parent;
217   else
218     return 0;
219 }
220 
glk_window_get_sibling(window_t * win)221 winid_t glk_window_get_sibling(window_t *win)
222 {
223   window_pair_t *dpairwin;
224   if (!win) {
225     gli_strict_warning("window_get_sibling: invalid ref");
226     return NULL;
227   }
228   if (!win->parent)
229     return NULL;
230   dpairwin = win->parent->data;
231   if (dpairwin->child1 == win)
232     return dpairwin->child2;
233   else if (dpairwin->child2 == win)
234     return dpairwin->child1;
235   else {
236     gli_strict_warning("window_get_sibling: damaged window tree");
237     return NULL;
238   }
239 }
240 
glk_window_get_size(window_t * win,glui32 * width,glui32 * height)241 void glk_window_get_size(window_t *win, glui32 *width, glui32 *height)
242 {
243   glui32 wid = 0;
244   glui32 hgt = 0;
245 
246   if (!win) {
247     gli_strict_warning("window_get_size: invalid ref");
248     return;
249   }
250 
251   switch (win->type) {
252   case wintype_Blank:
253   case wintype_Pair:
254     /* always zero */
255     break;
256   case wintype_TextGrid:
257     win_textgrid_get_size(win, &wid, &hgt);
258     break;
259   case wintype_TextBuffer:
260     win_textbuffer_get_size(win, &wid, &hgt);
261     break;
262   case wintype_Graphics:
263     win_graphics_get_size(win, &wid, &hgt);
264     break;
265   }
266 
267   if (width)
268     *width = wid;
269   if (height)
270     *height = hgt;
271 }
272 
glk_window_open(winid_t splitwin,glui32 method,glui32 size,glui32 wintype,glui32 rock)273 winid_t glk_window_open(winid_t splitwin, glui32 method, glui32 size,
274   glui32 wintype, glui32 rock)
275 {
276   window_t *newwin, *pairwin, *oldparent;
277   window_pair_t *dpairwin;
278   XRectangle box, *boxptr;
279   glui32 val;
280 
281   if (!gli_rootwin) {
282     if (splitwin) {
283       gli_strict_warning("window_open: id must be 0");
284       return 0;
285     }
286     /* ignore method and size now */
287     oldparent = NULL;
288 
289     box = matte_box;
290 
291     box.x += (MATTE_WIDTH-1);
292     box.y += (MATTE_WIDTH-1);
293     box.width -= 2*(MATTE_WIDTH-1);
294     box.height -= 2*(MATTE_WIDTH-1);
295   }
296   else {
297 
298     if (!splitwin) {
299       gli_strict_warning("window_open: invalid ref");
300       return 0;
301     }
302 
303     val = (method & winmethod_DivisionMask);
304     if (val != winmethod_Fixed && val != winmethod_Proportional) {
305       gli_strict_warning(
306 	"window_open: invalid method (not fixed or proportional)");
307       return 0;
308     }
309 
310     val = (method & winmethod_DirMask);
311     if (val != winmethod_Above && val != winmethod_Below
312       && val != winmethod_Left && val != winmethod_Right) {
313       gli_strict_warning("window_open: invalid method (bad direction)");
314       return 0;
315     }
316 
317     boxptr = gli_window_get_rect(splitwin);
318     if (!boxptr) {
319       gli_strict_warning("window_open: can't get window rect");
320       return 0;
321     }
322     box = *boxptr;
323 
324     oldparent = splitwin->parent;
325     if (oldparent && oldparent->type != wintype_Pair) {
326       gli_strict_warning("window_open: parent window is not Pair");
327       return 0;
328     }
329 
330   }
331 
332   newwin = gli_new_window(wintype, rock);
333   if (!newwin) {
334     gli_strict_warning("window_open: unable to create window");
335     return 0;
336   }
337   switch (wintype) {
338   case wintype_Blank:
339     newwin->data = win_blank_create(newwin);
340     break;
341   case wintype_TextGrid:
342     newwin->data = win_textgrid_create(newwin);
343     break;
344   case wintype_TextBuffer:
345     newwin->data = win_textbuffer_create(newwin);
346     break;
347   case wintype_Graphics:
348     newwin->data = win_graphics_create(newwin);
349     break;
350   case wintype_Pair:
351     gli_strict_warning("window_open: cannot open pair window directly");
352     gli_delete_window(newwin);
353     return 0;
354   default:
355     /* Unknown window type -- do not print a warning, just return 0
356        to indicate that it's not possible. */
357     gli_delete_window(newwin);
358     return 0;
359   }
360 
361   if (!newwin->data) {
362     gli_strict_warning("window_open: unable to create window");
363     return 0;
364   }
365 
366   if (!splitwin) {
367     gli_rootwin = newwin;
368     gli_window_rearrange(newwin, &box);
369   }
370   else {
371     /* create pairwin, with newwin as the key */
372     pairwin = gli_new_window(wintype_Pair, 0);
373     dpairwin = win_pair_create(pairwin, method, newwin, size);
374     pairwin->data = dpairwin;
375 
376     dpairwin->child1 = splitwin;
377     dpairwin->child2 = newwin;
378 
379     splitwin->parent = pairwin;
380     newwin->parent = pairwin;
381     pairwin->parent = oldparent;
382 
383     if (oldparent) {
384       window_pair_t *dparentwin = oldparent->data;
385       if (dparentwin->child1 == splitwin)
386 	dparentwin->child1 = pairwin;
387       else
388 	dparentwin->child2 = pairwin;
389     }
390     else {
391       gli_rootwin = pairwin;
392     }
393 
394     gli_window_rearrange(pairwin, &box);
395   }
396 
397   /* We don't send an event, because we're not in a select(). The user has
398      to know what to redraw. */
399 
400   /* Redraw the box area. */
401   box.x -= (MATTE_WIDTH-1);
402   box.y -= (MATTE_WIDTH-1);
403   box.width += 2*(MATTE_WIDTH-1);
404   box.height += 2*(MATTE_WIDTH-1);
405   xglk_invalidate(&box);
406 
407   return newwin;
408 }
409 
glk_window_get_arrangement(window_t * win,glui32 * method,glui32 * size,winid_t * keywin_id)410 void glk_window_get_arrangement(window_t *win, glui32 *method, glui32 *size,
411   winid_t *keywin_id)
412 {
413   window_pair_t *dwin;
414   glui32 val;
415 
416   if (!win) {
417     gli_strict_warning("window_get_arrangement: invalid ref");
418     return;
419   }
420 
421   if (win->type != wintype_Pair) {
422     gli_strict_warning("window_get_arrangement: not a Pair window");
423     return;
424   }
425 
426   dwin = win->data;
427 
428   val = dwin->dir | dwin->division;
429 
430   if (size)
431     *size = dwin->size;
432   if (keywin_id) {
433     if (dwin->key)
434       *keywin_id = dwin->key;
435     else
436       *keywin_id = 0;
437   }
438   if (method)
439     *method = val;
440 }
441 
glk_window_set_arrangement(window_t * win,glui32 method,glui32 size,winid_t key)442 void glk_window_set_arrangement(window_t *win, glui32 method, glui32 size, winid_t key)
443 {
444   window_pair_t *dwin;
445   glui32 newdir;
446   XRectangle box;
447   int newvertical, newbackward;
448 
449   if (!win) {
450     gli_strict_warning("window_set_arrangement: invalid ref");
451     return;
452   }
453 
454   if (win->type != wintype_Pair) {
455     gli_strict_warning("window_set_arrangement: not a Pair window");
456     return;
457   }
458 
459   if (key) {
460     window_t *wx;
461     if (key->type == wintype_Pair) {
462       gli_strict_warning("window_set_arrangement: keywin cannot be a Pair");
463       return;
464     }
465     for (wx=key; wx; wx=wx->parent) {
466       if (wx == win)
467 	break;
468     }
469     if (wx == NULL) {
470       gli_strict_warning("window_set_arrangement: keywin must be a descendant");
471       return;
472     }
473   }
474 
475   dwin = win->data;
476   box = dwin->bbox;
477 
478   newdir = method & winmethod_DirMask;
479   newvertical = (newdir == winmethod_Left || newdir == winmethod_Right);
480   newbackward = (newdir == winmethod_Left || newdir == winmethod_Above);
481   if (!key)
482     key = dwin->key;
483 
484   if ((newvertical && !dwin->vertical) || (!newvertical && dwin->vertical)) {
485     if (!dwin->vertical)
486       gli_strict_warning("window_set_arrangement: split must stay horizontal");
487     else
488       gli_strict_warning("window_set_arrangement: split must stay vertical");
489     return;
490   }
491 
492   if (key && key->type == wintype_Blank
493     && (method & winmethod_DivisionMask) == winmethod_Fixed) {
494     gli_strict_warning("window_set_arrangement: a Blank window cannot have a fixed size");
495     return;
496   }
497 
498   if ((newbackward && !dwin->backward) || (!newbackward && dwin->backward)) {
499     /* switch the children */
500     window_t *tmpwin = dwin->child1;
501     dwin->child1 = dwin->child2;
502     dwin->child2 = tmpwin;
503   }
504 
505   /* set up everything else */
506   dwin->dir = newdir;
507   dwin->division = method & winmethod_DivisionMask;
508   dwin->key = key;
509   dwin->size = size;
510 
511   dwin->vertical = (dwin->dir == winmethod_Left || dwin->dir == winmethod_Right);
512   dwin->backward = (dwin->dir == winmethod_Left || dwin->dir == winmethod_Above);
513 
514   gli_window_rearrange(win, &box);
515 
516   /* We don't send an event, because we're not in a select().
517      The user has to know what to redraw. */
518   box.x -= (MATTE_WIDTH-1);
519   box.y -= (MATTE_WIDTH-1);
520   box.width += 2*(MATTE_WIDTH-1);
521   box.height += 2*(MATTE_WIDTH-1);
522   xglk_invalidate(&box);
523 }
524 
gli_window_close(window_t * win,int recurse)525 static void gli_window_close(window_t *win, int recurse)
526 {
527   window_t *wx;
528 
529   if (gli_focuswin == win) {
530     /* gli_set_focus(NULL); */ /* We skip this, because it only does drawing,
531        and the whole area will be redrawn anyway. */
532     gli_focuswin = NULL;
533   }
534 
535   for (wx=win->parent; wx; wx=wx->parent) {
536     if (wx->type == wintype_Pair) {
537       window_pair_t *dwx = wx->data;
538       if (dwx->key == win) {
539 	dwx->key = NULL;
540 	dwx->keydamage = TRUE;
541       }
542     }
543   }
544 
545   switch (win->type) {
546   case wintype_Blank: {
547     window_blank_t *dwin = win->data;
548     win_blank_destroy(dwin);
549   }
550   break;
551   case wintype_Pair: {
552     window_pair_t *dwin = win->data;
553     if (recurse) {
554       if (dwin->child1)
555 	gli_window_close(dwin->child1, TRUE);
556       if (dwin->child2)
557 	gli_window_close(dwin->child2, TRUE);
558     }
559     win_pair_destroy(dwin);
560   }
561   break;
562   case wintype_TextBuffer: {
563     window_textbuffer_t *dwin = win->data;
564     win_textbuffer_destroy(dwin);
565   }
566   break;
567   case wintype_TextGrid: {
568     window_textgrid_t *dwin = win->data;
569     win_textgrid_destroy(dwin);
570   }
571   break;
572   case wintype_Graphics: {
573     window_graphics_t *dwin = win->data;
574     win_graphics_destroy(dwin);
575   }
576   break;
577   }
578 
579   gli_delete_window(win);
580 }
581 
glk_window_close(window_t * win,stream_result_t * result)582 void glk_window_close(window_t *win, stream_result_t *result)
583 {
584   XRectangle box, *boxptr;
585 
586   if (!win) {
587     gli_strict_warning("window_close: invalid ref");
588     return;
589   }
590 
591   if (win == gli_rootwin || win->parent == NULL) {
592     /* close the root window, which means all windows. */
593 
594     gli_rootwin = 0;
595 
596     /* begin (simpler) closation */
597 
598     boxptr = gli_window_get_rect(win);
599     if (!boxptr) {
600       gli_strict_warning("window_close: can't get window rect");
601       return;
602     }
603     box = *boxptr;
604 
605     gli_stream_fill_result(win->str, result);
606     gli_window_close(win, TRUE);
607 
608     box.x -= (MATTE_WIDTH-1);
609     box.y -= (MATTE_WIDTH-1);
610     box.width += 2*(MATTE_WIDTH-1);
611     box.height += 2*(MATTE_WIDTH-1);
612     xglk_invalidate(&box);
613   }
614   else {
615     /* have to jigger parent */
616     window_t *pairwin, *sibwin, *grandparwin, *wx;
617     window_pair_t *dpairwin, *dgrandparwin, *dwx;
618     int keydamage_flag;
619 
620     pairwin = win->parent;
621     dpairwin = pairwin->data;
622     if (win == dpairwin->child1) {
623       sibwin = dpairwin->child2;
624     }
625     else if (win == dpairwin->child2) {
626       sibwin = dpairwin->child1;
627     }
628     else {
629       gli_strict_warning("window_close: window tree is corrupted");
630       return;
631     }
632 
633     boxptr = gli_window_get_rect(pairwin);
634     if (!boxptr) {
635       gli_strict_warning("window_close: can't get window rect");
636       return;
637     }
638     box = *boxptr;
639 
640     grandparwin = pairwin->parent;
641     if (!grandparwin) {
642       gli_rootwin = sibwin;
643       sibwin->parent = NULL;
644     }
645     else {
646       dgrandparwin = grandparwin->data;
647       if (dgrandparwin->child1 == pairwin)
648 	dgrandparwin->child1 = sibwin;
649       else
650 	dgrandparwin->child2 = sibwin;
651       sibwin->parent = grandparwin;
652     }
653 
654     /* Begin closation */
655 
656     gli_stream_fill_result(win->str, result);
657 
658     /* Close the child window (and descendants), so that key-deletion can
659        crawl up the tree to the root window. */
660     gli_window_close(win, TRUE);
661 
662     /* This probably isn't necessary, but the child *is* gone, so just in case. */
663     if (win == dpairwin->child1) {
664       dpairwin->child1 = NULL;
665     }
666     else if (win == dpairwin->child2) {
667       dpairwin->child2 = NULL;
668     }
669 
670     /* Now we can delete the parent pair. */
671     gli_window_close(pairwin, FALSE);
672 
673     keydamage_flag = FALSE;
674     for (wx=sibwin; wx; wx=wx->parent) {
675       if (wx->type == wintype_Pair) {
676 	window_pair_t *dwx = wx->data;
677 	if (dwx->keydamage) {
678 	  keydamage_flag = TRUE;
679 	  dwx->keydamage = FALSE;
680 	}
681       }
682     }
683 
684     if (keydamage_flag) {
685       box = matte_box;
686 
687       box.x += (MATTE_WIDTH-1);
688       box.y += (MATTE_WIDTH-1);
689       box.width -= 2*(MATTE_WIDTH-1);
690       box.height -= 2*(MATTE_WIDTH-1);
691 
692       gli_window_rearrange(gli_rootwin, &box);
693 
694       xglk_invalidate(&matte_box);
695     }
696     else {
697       gli_window_rearrange(sibwin, &box);
698 
699       /* We don't send an event, because we're not in a select(). The user
700 	 has to know what to redraw. */
701 
702       box.x -= (MATTE_WIDTH-1);
703       box.y -= (MATTE_WIDTH-1);
704       box.width += 2*(MATTE_WIDTH-1);
705       box.height += 2*(MATTE_WIDTH-1);
706       xglk_invalidate(&box);
707     }
708   }
709 }
710 
711 /* The idea of the flush is that it happens before any entry to
712    glk_select(), which takes care of dirty data in valid regions.
713    It would be really cool if this clipped to the valid region,
714    and the exposure stuff clipped to invalid, but that's hard in X. */
gli_windows_flush()715 void gli_windows_flush()
716 {
717   int ix;
718   window_t *win;
719 
720   for (win = gli_windowlist; win; win = win->chain_next) {
721     switch (win->type) {
722     case wintype_TextBuffer:
723       win_textbuffer_flush(win);
724       break;
725     case wintype_TextGrid:
726       win_textgrid_flush(win);
727       break;
728     case wintype_Graphics:
729       win_graphics_flush(win);
730       break;
731     }
732   }
733 }
734 
glk_window_clear(window_t * win)735 void glk_window_clear(window_t *win)
736 {
737   if (!win) {
738     gli_strict_warning("window_clear: invalid ref");
739     return;
740   }
741 
742   if (win->line_request) {
743     gli_strict_warning("window_clear: window has pending line request");
744     return;
745   }
746 
747   switch (win->type) {
748   case wintype_TextBuffer:
749     win_textbuffer_clear_window(win->data);
750     break;
751   case wintype_TextGrid:
752     win_textgrid_clear_window(win->data);
753     break;
754   case wintype_Graphics:
755     win_graphics_erase_rect(win->data, TRUE, 0, 0, 0, 0);
756     break;
757   }
758 }
759 
glk_window_move_cursor(window_t * win,glui32 xpos,glui32 ypos)760 void glk_window_move_cursor(window_t *win, glui32 xpos, glui32 ypos)
761 {
762   if (!win) {
763     gli_strict_warning("window_move_cursor: invalid ref");
764     return;
765   }
766 
767   switch (win->type) {
768   case wintype_TextGrid:
769     win_textgrid_set_pos(win->data, xpos, ypos);
770     break;
771   default:
772     gli_strict_warning("window_move_cursor: not a TextGrid window");
773     break;
774   }
775 }
776 
glk_window_get_stream(window_t * win)777 strid_t glk_window_get_stream(window_t *win)
778 {
779   if (!win) {
780     gli_strict_warning("window_get_stream: invalid ref");
781     return 0;
782   }
783 
784   return win->str;
785 }
786 
glk_window_get_echo_stream(window_t * win)787 strid_t glk_window_get_echo_stream(window_t *win)
788 {
789   if (!win) {
790     gli_strict_warning("window_get_echo_stream: invalid ref");
791     return 0;
792   }
793 
794   if (win->echostr)
795     return win->echostr;
796   else
797     return 0;
798 }
799 
glk_window_set_echo_stream(window_t * win,stream_t * str)800 void glk_window_set_echo_stream(window_t *win, stream_t *str)
801 {
802   if (!win) {
803     gli_strict_warning("window_set_echo_stream: invalid window id");
804     return;
805   }
806 
807   win->echostr = str;
808 }
809 
glk_set_window(window_t * win)810 void glk_set_window(window_t *win)
811 {
812   if (!win) {
813     glk_stream_set_current(NULL);
814     return;
815   }
816 
817   glk_stream_set_current(win->str);
818 }
819 
gli_window_get_fontset(window_t * win)820 fontset_t *gli_window_get_fontset(window_t *win)
821 {
822   switch (win->type) {
823   case wintype_TextBuffer:
824     return win_textbuffer_get_fontset(win);
825     break;
826   case wintype_TextGrid:
827     return win_textgrid_get_fontset(win);
828     break;
829   default:
830     return NULL;
831   }
832 }
833 
gli_window_setfocus(window_t * win,int turnon)834 static void gli_window_setfocus(window_t *win, int turnon)
835 {
836   gli_draw_window_highlight(win, turnon);
837 
838   switch (win->type) {
839   case wintype_TextBuffer:
840     win_textbuffer_setfocus(win, turnon);
841     break;
842   case wintype_TextGrid:
843     win_textgrid_setfocus(win, turnon);
844     break;
845   }
846 }
847 
gli_set_focus(window_t * win)848 void gli_set_focus(window_t *win)
849 {
850   if (win == gli_focuswin)
851     return;
852 
853   if (gli_focuswin) {
854     gli_window_setfocus(gli_focuswin, FALSE);
855   }
856 
857   gli_focuswin = win;
858 
859   if (gli_focuswin) {
860     gli_window_setfocus(gli_focuswin, TRUE);
861   }
862 }
863 
gli_find_window_by_point(window_t * win,XPoint * pt)864 window_t *gli_find_window_by_point(window_t *win, XPoint *pt)
865 {
866   window_t *subwin;
867   window_pair_t *dwin;
868   int res;
869 
870   if (!win)
871     return NULL;
872 
873   if (win == gli_rootwin) {
874     if (pt->x < matte_box.x + (MATTE_WIDTH-1)
875       || pt->x >= matte_box.x+matte_box.width - (MATTE_WIDTH-1)
876       || pt->y < matte_box.y + (MATTE_WIDTH-1)
877       || pt->y >= matte_box.y+matte_box.height - (MATTE_WIDTH-1)) {
878       return NULL;
879     }
880   }
881 
882   if (win->type != wintype_Pair)
883     return win;
884 
885   dwin = win->data;
886   if (dwin->vertical) {
887     int val = dwin->bbox.x + dwin->splithgt;
888     if (pt->x >= val - (MATTE_WIDTH/2)
889       && pt->x < val - (MATTE_WIDTH/2) + MATTE_WIDTH) {
890       return win;
891     }
892     res = (pt->x >= val);
893   }
894   else {
895     int val = dwin->bbox.y + dwin->splithgt;
896     if (pt->y >= val - (MATTE_WIDTH/2)
897       && pt->y < val - (MATTE_WIDTH/2) + MATTE_WIDTH) {
898       return win;
899     }
900     res = (pt->y >= val);
901   }
902 
903   if (dwin->backward)
904     res = !res;
905   if (res)
906     subwin = dwin->child2;
907   else
908     subwin = dwin->child1;
909   return gli_find_window_by_point(subwin, pt);
910 }
911 
gli_window_rearrange(window_t * win,XRectangle * box)912 void gli_window_rearrange(window_t *win, XRectangle *box)
913 {
914   switch (win->type) {
915   case wintype_Blank:
916     win_blank_rearrange(win, box);
917     break;
918   case wintype_Pair:
919     win_pair_rearrange(win, box);
920     break;
921   case wintype_TextGrid:
922     win_textgrid_rearrange(win, box);
923     break;
924   case wintype_TextBuffer:
925     win_textbuffer_rearrange(win, box);
926     break;
927   case wintype_Graphics:
928     win_graphics_rearrange(win, box);
929     break;
930   }
931 }
932 
gli_window_redraw(window_t * win)933 void gli_window_redraw(window_t *win)
934 {
935   switch (win->type) {
936   case wintype_Blank:
937     win_blank_redraw(win);
938     break;
939   case wintype_Pair:
940     win_pair_redraw(win);
941     break;
942   case wintype_TextGrid:
943     win_textgrid_redraw(win);
944     break;
945   case wintype_TextBuffer:
946     win_textbuffer_redraw(win);
947     break;
948   case wintype_Graphics:
949     win_graphics_redraw(win);
950     break;
951   }
952 }
953 
gli_windows_set_paging(int forcetoend)954 void gli_windows_set_paging(int forcetoend)
955 {
956   window_t *win;
957 
958   for (win=gli_window_fixiterate(NULL);
959        win;
960        win=gli_window_fixiterate(win)) {
961     switch (win->type) {
962     case wintype_TextBuffer:
963       win_textbuffer_set_paging(win->data, forcetoend);
964       break;
965     }
966   }
967 }
968 
gli_windows_trim_buffers()969 void gli_windows_trim_buffers()
970 {
971   window_t *win;
972 
973   for (win=gli_window_fixiterate(NULL);
974        win;
975        win=gli_window_fixiterate(win)) {
976     switch (win->type) {
977     case wintype_TextBuffer:
978       win_textbuffer_trim_buffer(win->data);
979       break;
980     }
981   }
982 }
983 
gli_window_perform_click(window_t * win,int dir,XPoint * pt,int butnum,int clicknum,unsigned int state)984 void gli_window_perform_click(window_t *win, int dir, XPoint *pt, int butnum,
985   int clicknum, unsigned int state)
986 {
987   switch (win->type) {
988   case wintype_TextGrid:
989     win_textgrid_perform_click(win, dir, pt, butnum, clicknum, state);
990     break;
991   case wintype_TextBuffer:
992     win_textbuffer_perform_click(win, dir, pt, butnum, clicknum, state);
993     break;
994   case wintype_Graphics:
995     win_graphics_perform_click(win, dir, pt, butnum, clicknum, state);
996     break;
997   }
998 }
999 
gli_window_get_rect(window_t * win)1000 XRectangle *gli_window_get_rect(window_t *win)
1001 {
1002   switch (win->type) {
1003   case wintype_Blank: {
1004     window_blank_t *dwin = win->data;
1005     return &dwin->bbox;
1006   }
1007   case wintype_Pair: {
1008     window_pair_t *dwin = win->data;
1009     return &dwin->bbox;
1010   }
1011   case wintype_TextGrid:
1012     return win_textgrid_get_rect(win);
1013   case wintype_TextBuffer:
1014     return win_textbuffer_get_rect(win);
1015   case wintype_Graphics:
1016     return win_graphics_get_rect(win);
1017   default:
1018     return NULL;
1019   }
1020 }
1021 
glk_request_char_event(window_t * win)1022 void glk_request_char_event(window_t *win)
1023 {
1024   if (!win) {
1025     gli_strict_warning("request_char_event: invalid ref");
1026     return;
1027   }
1028 
1029   if (win->char_request || win->line_request) {
1030     gli_strict_warning("request_char_event: window already has keyboard request");
1031     return;
1032   }
1033 
1034   switch (win->type) {
1035   case wintype_TextBuffer:
1036   case wintype_TextGrid:
1037     win->char_request = TRUE;
1038     break;
1039   default:
1040     gli_strict_warning("request_char_event: window does not support keyboard input");
1041     break;
1042   }
1043 
1044 }
1045 
glk_cancel_char_event(window_t * win)1046 void glk_cancel_char_event(window_t *win)
1047 {
1048   if (!win) {
1049     gli_strict_warning("cancel_char_event: invalid ref");
1050     return;
1051   }
1052 
1053   switch (win->type) {
1054   case wintype_TextBuffer:
1055   case wintype_TextGrid:
1056     win->char_request = FALSE;
1057     break;
1058   default:
1059     /* do nothing */
1060     break;
1061   }
1062 }
1063 
glk_request_line_event(window_t * win,char * buf,glui32 maxlen,glui32 initlen)1064 void glk_request_line_event(window_t *win, char *buf, glui32 maxlen,
1065   glui32 initlen)
1066 {
1067   if (!win) {
1068     gli_strict_warning("request_line_event: invalid ref");
1069     return;
1070   }
1071 
1072   if (win->char_request || win->line_request) {
1073     gli_strict_warning("request_line_event: window already has keyboard request");
1074     return;
1075   }
1076 
1077   switch (win->type) {
1078   case wintype_TextBuffer:
1079     win->line_request = TRUE;
1080     win_textbuffer_init_line(win, buf, maxlen, initlen);
1081     break;
1082   case wintype_TextGrid:
1083     win->line_request = TRUE;
1084     win_textgrid_init_line(win, buf, maxlen, initlen);
1085     break;
1086   default:
1087     gli_strict_warning("request_line_event: window does not support keyboard input");
1088     break;
1089   }
1090 
1091 }
1092 
glk_cancel_line_event(window_t * win,event_t * ev)1093 void glk_cancel_line_event(window_t *win, event_t *ev)
1094 {
1095   event_t dummyev;
1096 
1097   if (!ev) {
1098     ev = &dummyev;
1099   }
1100 
1101   gli_event_clearevent(ev);
1102 
1103   if (!win) {
1104     gli_strict_warning("cancel_line_event: invalid ref");
1105     return;
1106   }
1107 
1108   switch (win->type) {
1109   case wintype_TextBuffer:
1110     if (win->line_request) {
1111       win_textbuffer_cancel_line(win, ev);
1112     }
1113     break;
1114   case wintype_TextGrid:
1115     if (win->line_request) {
1116       win_textgrid_cancel_line(win, ev);
1117     }
1118     break;
1119   default:
1120     /* do nothing */
1121     break;
1122   }
1123 }
1124 
glk_request_mouse_event(window_t * win)1125 void glk_request_mouse_event(window_t *win)
1126 {
1127   if (!win) {
1128     gli_strict_warning("request_mouse_event: invalid ref");
1129     return;
1130   }
1131 
1132   switch (win->type) {
1133   case wintype_Graphics:
1134   case wintype_TextGrid:
1135     win->mouse_request = TRUE;
1136     break;
1137   default:
1138     /* do nothing */
1139     break;
1140   }
1141 
1142   return;
1143 }
1144 
glk_cancel_mouse_event(window_t * win)1145 void glk_cancel_mouse_event(window_t *win)
1146 {
1147   if (!win) {
1148     gli_strict_warning("cancel_mouse_event: invalid ref");
1149     return;
1150   }
1151 
1152   switch (win->type) {
1153   case wintype_Graphics:
1154   case wintype_TextGrid:
1155     win->mouse_request = FALSE;
1156     break;
1157   default:
1158     /* do nothing */
1159     break;
1160   }
1161 
1162   return;
1163 }
1164 
glk_request_hyperlink_event(window_t * win)1165 void glk_request_hyperlink_event(window_t *win)
1166 {
1167   if (!win) {
1168     gli_strict_warning("request_hyperlink_event: invalid ref");
1169     return;
1170   }
1171 
1172   switch (win->type) {
1173   case wintype_TextBuffer:
1174   case wintype_TextGrid:
1175     win->hyperlink_request = TRUE;
1176     break;
1177   default:
1178     /* do nothing */
1179     break;
1180   }
1181 
1182   return;
1183 }
1184 
glk_cancel_hyperlink_event(window_t * win)1185 void glk_cancel_hyperlink_event(window_t *win)
1186 {
1187   if (!win) {
1188     gli_strict_warning("cancel_hyperlink_event: invalid ref");
1189     return;
1190   }
1191 
1192   switch (win->type) {
1193   case wintype_Graphics:
1194   case wintype_TextGrid:
1195     win->hyperlink_request = FALSE;
1196     break;
1197   default:
1198     /* do nothing */
1199     break;
1200   }
1201 
1202   return;
1203 }
1204 
gli_window_put_char(window_t * win,unsigned char ch)1205 void gli_window_put_char(window_t *win, unsigned char ch)
1206 {
1207   switch (win->type) {
1208   case wintype_TextBuffer:
1209     win_textbuffer_add(win->data, ch, -1);
1210     break;
1211   case wintype_TextGrid:
1212     win_textgrid_add(win->data, ch);
1213     break;
1214   }
1215 }
1216 
gli_window_set_style(window_t * win,glui32 val)1217 void gli_window_set_style(window_t *win, glui32 val)
1218 {
1219   win->style = val;
1220 
1221   switch (win->type) {
1222   case wintype_TextBuffer:
1223     win_textbuffer_set_style_text(win->data, win->style);
1224     break;
1225     /* Don't need a TextGrid case, since the code in macstat.c puts
1226        in style info as characters are added. */
1227   }
1228 }
1229 
gli_window_set_hyperlink(window_t * win,glui32 linkval)1230 void gli_window_set_hyperlink(window_t *win, glui32 linkval)
1231 {
1232   win->linkid = linkval;
1233 
1234   switch (win->type) {
1235   case wintype_TextBuffer:
1236     win_textbuffer_set_style_link(win->data, win->linkid);
1237     break;
1238     /* Don't need a TextGrid case, since the code in macstat.c puts
1239        in style info as characters are added. */
1240   }
1241 }
1242 
glk_image_draw(winid_t win,glui32 image,glsi32 val1,glsi32 val2)1243 glui32 glk_image_draw(winid_t win, glui32 image, glsi32 val1, glsi32 val2)
1244 {
1245   picture_t *pic;
1246 
1247   switch (win->type) {
1248   case wintype_TextBuffer:
1249     pic = picture_find(image);
1250     if (!pic)
1251       return FALSE;
1252     win_textbuffer_set_style_image(win->data, image, val1,
1253       pic->width, pic->height);
1254     win_textbuffer_add(win->data, '*', -1);
1255     win_textbuffer_set_style_text(win->data, 0xFFFFFFFF);
1256     picture_release(pic);
1257     return TRUE;
1258   case wintype_Graphics:
1259     return win_graphics_draw_picture(win->data, image, val1, val2,
1260       FALSE, 0, 0);
1261   }
1262 
1263   return FALSE;
1264 }
1265 
glk_image_draw_scaled(winid_t win,glui32 image,glsi32 val1,glsi32 val2,glui32 width,glui32 height)1266 glui32 glk_image_draw_scaled(winid_t win, glui32 image, glsi32 val1, glsi32 val2,
1267   glui32 width, glui32 height)
1268 {
1269   picture_t *pic;
1270 
1271   switch (win->type) {
1272   case wintype_TextBuffer:
1273     pic = picture_find(image);
1274     if (!pic)
1275       return FALSE;
1276     win_textbuffer_set_style_image(win->data, image, val1, width, height);
1277     win_textbuffer_add(win->data, '*', -1);
1278     win_textbuffer_set_style_text(win->data, 0xFFFFFFFF);
1279     picture_release(pic);
1280     return TRUE;
1281   case wintype_Graphics:
1282     return win_graphics_draw_picture(win->data, image, val1, val2,
1283       TRUE, width, height);
1284   }
1285 
1286   return FALSE;
1287 }
1288 
glk_image_get_info(glui32 image,glui32 * width,glui32 * height)1289 glui32 glk_image_get_info(glui32 image, glui32 *width, glui32 *height)
1290 {
1291   picture_t *pic = picture_find(image);
1292   if (!pic)
1293     return FALSE;
1294 
1295   if (width)
1296     *width = pic->width;
1297   if (height)
1298     *height = pic->height;
1299 
1300   picture_release(pic);
1301   return TRUE;
1302 }
1303 
glk_window_flow_break(winid_t win)1304 void glk_window_flow_break(winid_t win)
1305 {
1306   switch (win->type) {
1307   case wintype_TextBuffer:
1308     win_textbuffer_set_style_break(win->data);
1309     win_textbuffer_add(win->data, '*', -1);
1310     win_textbuffer_set_style_text(win->data, 0xFFFFFFFF);
1311     break;
1312   }
1313 }
1314 
glk_window_erase_rect(winid_t win,glsi32 left,glsi32 top,glui32 width,glui32 height)1315 void glk_window_erase_rect(winid_t win,
1316   glsi32 left, glsi32 top, glui32 width, glui32 height)
1317 {
1318   if (!win) {
1319     gli_strict_warning("window_erase_rect: invalid ref");
1320     return;
1321   }
1322   if (win->type != wintype_Graphics) {
1323     gli_strict_warning("window_erase_rect: not a graphics window");
1324     return;
1325   }
1326   win_graphics_erase_rect(win->data, FALSE, left, top, width, height);
1327 }
1328 
glk_window_fill_rect(winid_t win,glui32 color,glsi32 left,glsi32 top,glui32 width,glui32 height)1329 void glk_window_fill_rect(winid_t win, glui32 color,
1330   glsi32 left, glsi32 top, glui32 width, glui32 height)
1331 {
1332   if (!win) {
1333     gli_strict_warning("window_fill_rect: invalid ref");
1334     return;
1335   }
1336   if (win->type != wintype_Graphics) {
1337     gli_strict_warning("window_fill_rect: not a graphics window");
1338     return;
1339   }
1340   win_graphics_fill_rect(win->data, color, left, top, width, height);
1341 }
1342 
glk_window_set_background_color(winid_t win,glui32 color)1343 void glk_window_set_background_color(winid_t win, glui32 color)
1344 {
1345   if (!win) {
1346     gli_strict_warning("window_set_background_color: invalid ref");
1347     return;
1348   }
1349   if (win->type != wintype_Graphics) {
1350     gli_strict_warning("window_set_background_color: not a graphics window");
1351     return;
1352   }
1353   win_graphics_set_background_color(win->data, color);
1354 }
1355 
1356 /* ----- subwindow functions ---------- */
1357 
win_blank_create(window_t * win)1358 window_blank_t *win_blank_create(window_t *win)
1359 {
1360   window_blank_t *dwin = (window_blank_t *)malloc(sizeof(window_blank_t));
1361   dwin->owner = win;
1362 
1363   return dwin;
1364 }
1365 
win_blank_destroy(window_blank_t * dwin)1366 void win_blank_destroy(window_blank_t *dwin)
1367 {
1368   dwin->owner = NULL;
1369   free(dwin);
1370 }
1371 
win_blank_rearrange(window_t * win,XRectangle * box)1372 void win_blank_rearrange(window_t *win, XRectangle *box)
1373 {
1374   window_blank_t *dwin = win->data;
1375   dwin->bbox = *box;
1376 }
1377 
win_blank_redraw(window_t * win)1378 void win_blank_redraw(window_t *win)
1379 {
1380   window_blank_t *dwin = win->data;
1381   gli_draw_window_outline(&dwin->bbox);
1382 
1383   XFillRectangle(xiodpy, xiowin, gctech, dwin->bbox.x, dwin->bbox.y,
1384     dwin->bbox.width, dwin->bbox.height);
1385 }
1386 
win_pair_create(window_t * win,glui32 method,window_t * key,glui32 size)1387 window_pair_t *win_pair_create(window_t *win, glui32 method, window_t *key,
1388   glui32 size)
1389 {
1390   window_pair_t *dwin = (window_pair_t *)malloc(sizeof(window_pair_t));
1391   dwin->owner = win;
1392 
1393   dwin->dir = method & winmethod_DirMask;
1394   dwin->division = method & winmethod_DivisionMask;
1395   dwin->key = key;
1396   dwin->keydamage = FALSE;
1397   dwin->size = size;
1398 
1399   dwin->vertical =
1400     (dwin->dir == winmethod_Left || dwin->dir == winmethod_Right);
1401   dwin->backward =
1402     (dwin->dir == winmethod_Left || dwin->dir == winmethod_Above);
1403 
1404   dwin->child1 = NULL;
1405   dwin->child2 = NULL;
1406 
1407   return dwin;
1408 }
1409 
win_pair_destroy(window_pair_t * dwin)1410 void win_pair_destroy(window_pair_t *dwin)
1411 {
1412   dwin->owner = NULL;
1413   /* We leave the children untouched, because gli_window_close takes care
1414      of that if it's desired. */
1415   dwin->child1 = NULL;
1416   dwin->child2 = NULL;
1417   dwin->key = NULL;
1418   free(dwin);
1419 }
1420 
win_pair_rearrange(window_t * win,XRectangle * box)1421 void win_pair_rearrange(window_t *win, XRectangle *box)
1422 {
1423   window_pair_t *dwin = win->data;
1424   XRectangle box1, box2;
1425   long min, diff, split, max;
1426   window_t *key;
1427   window_t *ch1, *ch2;
1428 
1429   dwin->bbox = *box;
1430   dwin->flat = FALSE;
1431 
1432   if (dwin->vertical) {
1433     min = dwin->bbox.x;
1434     max = dwin->bbox.x+dwin->bbox.width;
1435   }
1436   else {
1437     min = dwin->bbox.y;
1438     max = dwin->bbox.y+dwin->bbox.height;
1439   }
1440   diff = max-min;
1441 
1442   switch (dwin->division) {
1443   case winmethod_Proportional:
1444     split = (diff * dwin->size) / 100;
1445     break;
1446   case winmethod_Fixed:
1447     key = dwin->key;
1448     if (!key) {
1449       split = 0;
1450     }
1451     else {
1452       switch (key->type) {
1453       case wintype_TextBuffer:
1454 	split = win_textbuffer_figure_size(key, dwin->size, dwin->vertical);
1455 	break;
1456       case wintype_TextGrid:
1457 	split = win_textgrid_figure_size(key, dwin->size, dwin->vertical);
1458 	break;
1459       case wintype_Graphics:
1460 	split = win_graphics_figure_size(key, dwin->size, dwin->vertical);
1461 	break;
1462       default:
1463 	split = 0;
1464 	break;
1465       }
1466     }
1467     split += HALF_MATTE_WIDTH; /* extra space for split bar */
1468     break;
1469   default:
1470     split = diff / 2;
1471     break;
1472   }
1473 
1474   if (!dwin->backward) {
1475     split = diff-split;
1476   }
1477   else {
1478     split = 0+split;
1479   }
1480 
1481   if (split < (MATTE_WIDTH/2))
1482     split = (MATTE_WIDTH/2);
1483   else if (split > diff - (MATTE_WIDTH - (MATTE_WIDTH/2)))
1484     split = diff - (MATTE_WIDTH - (MATTE_WIDTH/2));
1485 
1486   if (diff < MATTE_WIDTH) {
1487     /* blow off the whole routine */
1488     dwin->flat = TRUE;
1489     split = diff / 2;
1490   }
1491 
1492   if (dwin->vertical) {
1493     dwin->splithgt = split;
1494     if (dwin->flat) {
1495       box1.x = dwin->bbox.x+split;
1496       box1.width = 0;
1497       box2.x = dwin->bbox.x+split;
1498       box2.width = 0;
1499     }
1500     else {
1501       box1.x = dwin->bbox.x;
1502       box1.width = split - (MATTE_WIDTH/2);
1503       box2.x = box1.x + box1.width + MATTE_WIDTH;
1504       box2.width = dwin->bbox.x+dwin->bbox.width - box2.x;
1505     }
1506     box1.y = dwin->bbox.y;
1507     box1.height = dwin->bbox.height;
1508     box2.y = dwin->bbox.y;
1509     box2.height = dwin->bbox.height;
1510     if (!dwin->backward) {
1511       ch1 = dwin->child1;
1512       ch2 = dwin->child2;
1513     }
1514     else {
1515       ch1 = dwin->child2;
1516       ch2 = dwin->child1;
1517     }
1518   }
1519   else {
1520     dwin->splithgt = split;
1521     if (dwin->flat) {
1522       box1.y = dwin->bbox.y+split;
1523       box1.height = 0;
1524       box2.y = dwin->bbox.y+split;
1525       box2.height = 0;
1526     }
1527     else {
1528       box1.y = dwin->bbox.y;
1529       box1.height = split - (MATTE_WIDTH/2);
1530       box2.y = box1.y+box1.height + MATTE_WIDTH;
1531       box2.height = dwin->bbox.y+dwin->bbox.height - box2.y;
1532     }
1533     box1.x = dwin->bbox.x;
1534     box1.width = dwin->bbox.width;
1535     box2.x = dwin->bbox.x;
1536     box2.width = dwin->bbox.width;
1537     if (!dwin->backward) {
1538       ch1 = dwin->child1;
1539       ch2 = dwin->child2;
1540     }
1541     else {
1542       ch1 = dwin->child2;
1543       ch2 = dwin->child1;
1544     }
1545   }
1546 
1547   gli_window_rearrange(ch1, &box1);
1548   gli_window_rearrange(ch2, &box2);
1549 }
1550 
win_pair_redraw(window_t * win)1551 void win_pair_redraw(window_t *win)
1552 {
1553   XRectangle box;
1554   window_pair_t *dwin;
1555 
1556   if (!win)
1557     return;
1558 
1559   dwin = win->data;
1560 
1561   if (xiodepth > 1) {
1562     if (dwin->vertical) {
1563       box.y = dwin->bbox.y - MATTE_WIDTH/2;
1564       box.height = dwin->bbox.height + MATTE_WIDTH;
1565       box.x = dwin->bbox.x + dwin->splithgt - (MATTE_WIDTH/2);
1566       box.width = MATTE_WIDTH;
1567     }
1568     else {
1569       box.x = dwin->bbox.x - MATTE_WIDTH/2;
1570       box.width = dwin->bbox.width + MATTE_WIDTH;
1571       box.y = dwin->bbox.y + dwin->splithgt - (MATTE_WIDTH/2);
1572       box.height = MATTE_WIDTH;
1573     }
1574     XFillRectangle(xiodpy, xiowin, gctech, box.x, box.y,
1575       box.width, box.height);
1576   }
1577 
1578   gli_window_redraw(dwin->child1);
1579   gli_window_redraw(dwin->child2);
1580 }
1581 
xgc_movecursor(window_t * win,int op)1582 void xgc_movecursor(window_t *win, int op)
1583 {
1584   if (!win) {
1585     if (xmsg_msgmode == xmsg_mode_Line)
1586       xgc_msg_movecursor(op);
1587     else
1588       xmsg_set_message("invalid window for cursor movement", FALSE);
1589     return;
1590   }
1591 
1592   switch (win->type) {
1593   case wintype_TextBuffer:
1594     xgc_buf_movecursor(win->data, op);
1595     break;
1596   case wintype_TextGrid:
1597     xgc_grid_movecursor(win->data, op);
1598     break;
1599   default:
1600     xmsg_set_message("invalid window for cursor movement", FALSE);
1601     break;
1602   }
1603 }
1604 
xgc_scroll(window_t * win,int op)1605 void xgc_scroll(window_t *win, int op)
1606 {
1607   switch (win->type) {
1608   case wintype_TextBuffer:
1609     xgc_buf_scroll(win->data, op);
1610     break;
1611   default:
1612     xmsg_set_message("invalid window for scrolling", FALSE);
1613     break;
1614   }
1615 }
1616 
xgc_scrollto(window_t * win,int op)1617 void xgc_scrollto(window_t *win, int op)
1618 {
1619   switch (win->type) {
1620   case wintype_TextBuffer:
1621     xgc_buf_scrollto(win->data, op);
1622     break;
1623   default:
1624     xmsg_set_message("invalid window for scrolling", FALSE);
1625     break;
1626   }
1627 }
1628 
xgc_insert(window_t * win,int op)1629 void xgc_insert(window_t *win, int op)
1630 {
1631   if (!win) {
1632     if (xmsg_msgmode == xmsg_mode_Line)
1633       xgc_msg_insert(op);
1634     else
1635       xmsg_set_message("invalid window for inserting", FALSE);
1636     return;
1637   }
1638 
1639   switch (win->type) {
1640   case wintype_TextBuffer:
1641     xgc_buf_insert(win->data, op);
1642     break;
1643   case wintype_TextGrid:
1644     xgc_grid_insert(win->data, op);
1645     break;
1646   default:
1647     xmsg_set_message("invalid window for inserting", FALSE);
1648     break;
1649   }
1650 }
1651 
xgc_delete(window_t * win,int op)1652 void xgc_delete(window_t *win, int op)
1653 {
1654   if (!win) {
1655     if (xmsg_msgmode == xmsg_mode_Line)
1656       xgc_msg_delete(op);
1657     else
1658       xmsg_set_message("invalid window for deleting", FALSE);
1659     return;
1660   }
1661 
1662   switch (win->type) {
1663   case wintype_TextBuffer:
1664     xgc_buf_delete(win->data, op);
1665     break;
1666   case wintype_TextGrid:
1667     xgc_grid_delete(win->data, op);
1668     break;
1669   default:
1670     xmsg_set_message("invalid window for deleting", FALSE);
1671     break;
1672   }
1673 }
1674 
xgc_getchar(window_t * win,int op)1675 void xgc_getchar(window_t *win, int op)
1676 {
1677   if (!win) {
1678     if (xmsg_msgmode == xmsg_mode_Char)
1679       xgc_msg_getchar(op);
1680     else
1681       xmsg_set_message("invalid window for key entry", FALSE);
1682     return;
1683   }
1684 
1685   switch (win->type) {
1686   case wintype_TextBuffer:
1687     xgc_buf_getchar(win->data, op);
1688     break;
1689   case wintype_TextGrid:
1690     xgc_grid_getchar(win->data, op);
1691     break;
1692   default:
1693     xmsg_set_message("invalid window for key entry", FALSE);
1694     break;
1695   }
1696 }
1697 
xgc_enter(window_t * win,int op)1698 void xgc_enter(window_t *win, int op)
1699 {
1700   if (!win) {
1701     if (xmsg_msgmode == xmsg_mode_Line)
1702       xgc_msg_enter(op);
1703     else
1704       xmsg_set_message("invalid window for line entry", FALSE);
1705     return;
1706   }
1707 
1708   switch (win->type) {
1709   case wintype_TextBuffer:
1710     xgc_buf_enter(win->data, op);
1711     break;
1712   case wintype_TextGrid:
1713     xgc_grid_enter(win->data, op);
1714     break;
1715   default:
1716     xmsg_set_message("invalid window for line entry", FALSE);
1717     break;
1718   }
1719 }
1720 
xgc_cutbuf(window_t * win,int op)1721 void xgc_cutbuf(window_t *win, int op)
1722 {
1723   switch (win->type) {
1724   case wintype_TextBuffer:
1725     xgc_buf_cutbuf(win->data, op);
1726     break;
1727   case wintype_TextGrid:
1728     xgc_grid_cutbuf(win->data, op);
1729     break;
1730   default:
1731     xmsg_set_message("invalid window for cut/paste", FALSE);
1732     break;
1733   }
1734 }
1735 
xgc_history(window_t * win,int op)1736 void xgc_history(window_t *win, int op)
1737 {
1738   switch (win->type) {
1739   case wintype_TextBuffer:
1740     xgc_buf_history(win->data, op);
1741     break;
1742   default:
1743     xmsg_set_message("invalid window for command history", FALSE);
1744     break;
1745   }
1746 }
1747 
1748