]> git.neil.brown.name Git - edlib.git/blob - core-pane.c
1ba2bf1480f43669fa6a8364be6c12f0445c1912
[edlib.git] / core-pane.c
1 /*
2  * Copyright Neil Brown ©2015-2023 <neil@brown.name>
3  * May be distributed under terms of GPLv2 - see file:COPYING
4  *
5  * panes for edlib.
6  *
7  * There is a list of 'panes' which can display rendered content
8  * and can optionally receive input.
9  * A pane is registered as a child of an existing pane and indicates
10  * a 'z' depth, and whether it can take input.
11  *
12  * The owner of a pane can:
13  * - register sub-panes
14  * - ask for text to be rendered at any time,
15  * - can request or discard focus.  When discarded it returns to lower z level.
16  *
17  * The pane can tell the owner:
18  * - to refresh - possibly because it has been resized
19  * - that keyboard input has arrived
20  * - that a mouse click has arrived
21  *
22  * A pane can extend beyond the size of its parent, but is always
23  * clipped to the parent.  If two children of a parent overlap and
24  * have the same Z-depth the result is undefined.
25  */
26
27 #define _GNU_SOURCE /*  for asprintf */
28 #include <stdlib.h>
29 #include <time.h>
30 #include <string.h>
31 #include <wchar.h>
32 #include <ctype.h>
33 #include <stdio.h>
34
35 #include "core.h"
36 #include "internal.h"
37
38 MEMPOOL(pane);
39
40 static void pane_init(struct pane *p safe, struct pane *par)
41 {
42         if (par) {
43                 p->parent = par;
44                 list_add(&p->siblings, &par->children);
45                 p->root = par->root;
46         } else {
47                 p->parent = p;
48                 INIT_LIST_HEAD(&p->siblings);
49                 p->root = p;
50         }
51         INIT_LIST_HEAD(&p->children);
52         INIT_LIST_HEAD(&p->notifiers);
53         INIT_LIST_HEAD(&p->notifiees);
54         p->x = p->y = p->z = 0;
55         p->cx = p->cy = -1;
56         p->h = p->w = 0;
57         if (par) {
58                 /* reasonable defaults */
59                 p->w = par->w;
60                 p->h = par->h;
61         }
62         p->abs_z = 0;
63         p->focus = NULL;
64         p->handle = NULL;
65         p->damaged = 0;
66         p->attrs = NULL;
67         p->refs = 1;
68 }
69
70 static void _pane_check(struct pane *p safe)
71 {
72         struct pane *c;
73         list_for_each_entry(c, &p->children, siblings) {
74                 ASSERT(c->parent == p);
75                 _pane_check(c);
76         }
77 }
78
79 static void pane_check(struct pane *p safe)
80 {
81         _pane_check(pane_root(p));
82 }
83
84 DEF_CMD(pane_refresh);
85 /*
86  * pane_damaged: mark a pane as being 'damaged', and make
87  * sure all parents know about it.
88  */
89 void pane_damaged(struct pane *p, int type)
90 {
91         int z;
92         struct pane *orig = p;
93         int orig_type = type;
94         if (!p || (p->damaged | type) == p->damaged)
95                 return;
96         if (p == p->parent && !p->damaged)
97                 if (call_comm("event:on-idle", p, &pane_refresh, 1) <= 0)
98                         /* Cannot register an event yet, ignore damage */
99                         return;
100         if (type & (type-1)) {
101                 /* multiple bits are set, handle
102                  * them separately
103                  */
104                 int b;
105                 for (b = 1; type; b <<= 1) {
106                         if (b & type)
107                                 pane_damaged(p, b);
108                         type &= ~b;
109                 }
110                 return;
111         }
112         p->damaged |= type;
113
114         z = p->z;
115         if (z < 0)
116                 /* light-weight pane - never propagate damage */
117                 return;
118         if (type == DAMAGED_SIZE)
119                 type = DAMAGED_SIZE_CHILD;
120         else if (type == DAMAGED_VIEW)
121                 type = DAMAGED_VIEW_CHILD;
122         else if (type & DAMAGED_NEED_CALL)
123                 type = DAMAGED_CHILD;
124         else if (type == DAMAGED_POSTORDER)
125                 type = DAMAGED_POSTORDER_CHILD;
126         else
127                 return;
128
129         p->damaged |= type;
130         p = p->parent;
131         while ((p->damaged | type) != p->damaged) {
132                 if (p->damaged & DAMAGED_DEBUG) {
133                         LOG("damage %s %d (%d)", orig->name, orig_type, type);
134                         LOG_BT();
135                 }
136
137                 if (p == p->parent && !p->damaged)
138                         call_comm("event:on-idle", p, &pane_refresh, 1);
139
140                 if (z > 0 && (type & DAMAGED_SIZE_CHILD))
141                         /* overlay changed size, so we must refresh */
142                         /* FIXME should this be a notification? */
143                         p->damaged |= DAMAGED_REFRESH;
144                 p->damaged |= type;
145                 z = p->z;
146                 p = p->parent;
147         }
148 }
149
150 static struct pane *_do_pane_register(struct pane *parent, short z,
151                                        struct command *handle safe,
152                                        void *data, short data_size)
153 {
154         struct pane *p;
155         short alloc_size = data_size;
156
157         if (data)
158                 alloc_size = sizeof(data);
159         alloc_size += offsetof(struct pane, data);
160
161         p = alloc_zbuf(alloc_size, pane);
162         pane_init(p, parent);
163         p->alloc_size = alloc_size;
164         p->z = z;
165         if (parent)
166                 p->abs_z = parent->abs_z + 1;
167         p->handle = command_get(handle);
168         if (data)
169                 p->data = data;
170
171         p->name = handle->name;
172         if (z >= 0) {
173                 if (parent && parent->focus == NULL)
174                         parent->focus = p;
175                 if (pane_call(parent, "Child-Notify", p, 1) < 0 ||
176                     p->damaged & DAMAGED_CLOSED) {
177                         /* ChildRegistered objected */
178                         p->damaged |= DAMAGED_NOINIT;
179                         pane_close(p);
180                         p = NULL;
181                 } else if (parent && parent != pane_root(parent))
182                         /* Need to set size of child, but not
183                          * if parent is root and that make libevent
184                          * fail to load.
185                          */
186                         pane_damaged(parent, DAMAGED_SIZE);
187         }
188         return p;
189 }
190
191 struct pane *do_pane_register(struct pane *parent safe, short z,
192                               struct command *handle safe,
193                               void *data, short data_size)
194 {
195         return _do_pane_register(parent, z, handle, data, data_size);
196 }
197
198 struct pane *pane_register_root(struct command *handle safe,
199                                 void *data, short data_size)
200 {
201         return _do_pane_register(NULL, 0, handle, data, data_size);
202 }
203
204 void pane_update_handle(struct pane *p safe, struct command *handle safe)
205 {
206         command_put(p->handle);
207         p->handle = command_get(handle);
208 }
209
210 /* 'abs_z' is a global z-depth number (->z is relative to parent)
211  * 'abs_z' of root is 0, and abs_z of every other pane with z<=0 is 1 more than
212  * abs_z or parent, and abs_z of pane with z>0 is 1 more than max abs_z
213  * of all children of siblings with lower z.
214  */
215
216 static int pane_do_absz(struct pane *p safe, int absz)
217 {
218         int nextz = 0;
219         struct pane *c;
220
221         p->abs_z = absz;
222         absz += 1;
223         while (nextz >= 0) {
224                 int z = nextz;
225                 int next_absz = absz + 1;
226
227                 nextz = -1;
228                 list_for_each_entry(c, &p->children, siblings) {
229                         int t;
230
231                         if (c->z < 0 && z == 0) {
232                                 c->abs_z = p->abs_z + 1;
233                                 continue;
234                         }
235                         if (c->z < z)
236                                 continue;
237                         if (c->z > z) {
238                                 if (nextz < 0 || c->z < nextz)
239                                         nextz = c->z;
240                                 continue;
241                         }
242
243                         t = pane_do_absz(c, absz);
244                         if (t > next_absz)
245                                 next_absz = t;
246                 }
247                 absz = next_absz;
248         }
249         return absz + 1;
250 }
251
252 /*
253  * If DAMAGED_SIZE is set on a pane, we call "Refresh:size".
254  * If it or DAMAGED_SIZE_CHILD was set, we recurse onto all children.
255  * If abs_z is not one more than parent, we also recurse.
256  */
257 static void pane_do_resize(struct pane *p safe, int damage)
258 {
259         int loops = 0;
260         if (!(p->damaged & DAMAGED_SIZE_CHILD))
261                 return;
262
263         while (p->damaged & DAMAGED_SIZE_CHILD) {
264                 struct pane *parent, *c, *t;
265
266                 /* Find a child with DAMGED_SIZE_CHILD.
267                  * If it is DAMAGED_SIZE, handle that, else check
268                  * its children.  If no DAMAGED_SIZE_CHILD
269                  * children are found, clear DAMAGED_SIZE_CHILD.
270                  */
271                 c = p;
272                 while (c && !(c->damaged & DAMAGED_CLOSED)) {
273                         parent = c;
274                         c = NULL;
275                         if (parent->damaged & DAMAGED_SIZE) {
276                                 parent->damaged &= ~DAMAGED_SIZE;
277                                 loops += 1;
278                                 if (loops == 1000) {
279                                         LOG("pane resize looped 1000 times - some pane must keep damaging itself.");
280                                         call("editor:notify:Message:broadcast",
281                                              p, 0, NULL,
282                                              "WARNING pane resize loop - see log");
283                                 }
284                                 if (loops >= 1000)
285                                         break;
286
287                                 if (pane_call(parent, "Refresh:size",
288                                               parent) == Efallthrough) {
289                                         /* Need to resize children ourselves */
290                                         list_for_each_entry(c, &parent->children,
291                                                             siblings)
292                                                 if (c->z == 0)
293                                                         pane_resize(c, 0, 0,
294                                                                     parent->w,
295                                                                     parent->h);
296                                                 else if (c->z > 0)
297                                                         pane_damaged(c, DAMAGED_SIZE);
298                                 }
299                                 /* Need to restart from root */
300                                 break;
301                         }
302                         list_for_each_entry(t, &parent->children, siblings)
303                                 if (t->damaged & DAMAGED_SIZE_CHILD) {
304                                         c = t;
305                                         break;
306                                 }
307                         if (!c)
308                                 parent->damaged &= ~DAMAGED_SIZE_CHILD;
309                 }
310         }
311         pane_do_absz(p, 0);
312 }
313
314 static void pane_do_refresh(struct pane *p safe)
315 {
316         struct pane *c;
317         int damage;
318
319         if (p->damaged & DAMAGED_CLOSED)
320                 return;
321
322         damage = p->damaged & (DAMAGED_CHILD|DAMAGED_REFRESH);
323         if (!damage)
324                 return;
325         p->damaged &= ~damage;
326         if (damage & DAMAGED_REFRESH)
327                 pane_call(p, "Refresh", pane_leaf(p));
328
329         list_for_each_entry(c, &p->children, siblings)
330                 c->damaged |= DAMAGED_NOT_HANDLED;
331 restart:
332         list_for_each_entry(c, &p->children, siblings) {
333                 if (c->damaged & DAMAGED_NOT_HANDLED)
334                         c->damaged &= ~DAMAGED_NOT_HANDLED;
335                 else
336                         /* Only handle each pane once */
337                         continue;
338                 if (c->z >= 0) {
339                         pane_do_refresh(c);
340                         goto restart;
341                 }
342         }
343 }
344
345 static void pane_do_review(struct pane *p safe)
346 {
347         struct pane *c;
348         int damage;
349
350         if (p->damaged & DAMAGED_CLOSED)
351                 return;
352
353         damage = p->damaged & (DAMAGED_VIEW|DAMAGED_VIEW_CHILD);
354         p->damaged &= ~damage;
355         if (!damage)
356                 return;
357
358         if (damage & DAMAGED_VIEW)
359                 pane_call(p, "Refresh:view", pane_leaf(p));
360
361         list_for_each_entry(c, &p->children, siblings)
362                 c->damaged |= DAMAGED_NOT_HANDLED;
363 restart:
364         list_for_each_entry(c, &p->children, siblings) {
365                 if (c->damaged & DAMAGED_NOT_HANDLED)
366                         c->damaged &= ~DAMAGED_NOT_HANDLED;
367                 else
368                         /* Only handle each pane once */
369                         continue;
370                 if (c->z >= 0) {
371                         pane_do_review(c);
372                         goto restart;
373                 }
374         }
375 }
376
377 static void pane_do_postorder(struct pane *p safe)
378 {
379         struct pane *c;
380         int damage;
381
382         if (p->damaged & DAMAGED_CLOSED)
383                 return;
384
385         damage = p->damaged & (DAMAGED_POSTORDER|DAMAGED_POSTORDER_CHILD);
386         p->damaged &= ~(DAMAGED_POSTORDER|DAMAGED_POSTORDER_CHILD);
387         if (!damage)
388                 return;
389
390         list_for_each_entry(c, &p->children, siblings)
391                 c->damaged |= DAMAGED_NOT_HANDLED;
392 restart:
393         list_for_each_entry(c, &p->children, siblings) {
394                 if (c->damaged & DAMAGED_NOT_HANDLED)
395                         c->damaged &= ~DAMAGED_NOT_HANDLED;
396                 else
397                         /* Only handle each pane once */
398                         continue;
399                 pane_do_postorder(c);
400                 goto restart;
401         }
402         if (damage & DAMAGED_POSTORDER)
403                 call("Refresh:postorder", p);
404 }
405
406 REDEF_CMD(pane_refresh)
407 {
408         struct pane *p = ci->home;
409         int cnt = 5;
410
411         if (p->damaged & DAMAGED_CLOSED)
412                 return 1;
413
414         time_start(TIME_REFRESH);
415         while (cnt-- &&
416                (p->damaged &
417                 ~(DAMAGED_CLOSED|DAMAGED_POSTORDER|DAMAGED_POSTORDER_CHILD))) {
418                 if (cnt == 0)
419                         p->damaged |= DAMAGED_DEBUG;
420                 pane_do_resize(p, 0);
421                 pane_do_review(p);
422                 pane_do_refresh(p);
423                 p->damaged &= ~DAMAGED_DEBUG;
424         }
425         pane_do_postorder(p);
426         if (p->damaged) {
427                 static time_t last_warn;
428                 static int rpt;
429                 if (last_warn + 5 < time(NULL))
430                         rpt = 0;
431                 if (rpt++ < 5)
432                         LOG("WARNING %sroot pane damaged after refresh: %d",
433                             p->parent != p ? "":"non-", p->damaged);
434                 last_warn = time(NULL);
435                 call("editor:notify:Message:broadcast",p, 0, NULL,
436                      "Refresh looping - see log");
437         }
438         time_stop(TIME_REFRESH);
439         return 1;
440 }
441
442 void pane_add_notify(struct pane *target safe, struct pane *source safe,
443                      const char *msg safe)
444 {
445         struct notifier *n;
446
447         list_for_each_entry(n, &source->notifiees, notifier_link)
448                 if (n->notifiee == target &&
449                     strcmp(msg, n->notification) == 0)
450                         /* Already notifying */
451                         return;
452
453         alloc(n, pane);
454
455         n->notifiee = target;
456         n->notification = strdup(msg);
457         n->noted = 0;
458         list_add(&n->notifier_link, &source->notifiees);
459         list_add(&n->notifiee_link, &target->notifiers);
460 }
461
462 void pane_drop_notifiers(struct pane *p safe, char *notification)
463 {
464         struct list_head *t;
465         struct notifier *n;
466
467         list_for_each_entry_safe(n, t, &p->notifiers, notifiee_link) {
468
469                 if (notification && strcmp(notification, n->notification) != 0)
470                         continue;
471                 list_del_init(&n->notifiee_link);
472                 list_del_init(&n->notifier_link);
473                 free(n->notification);
474                 free(n);
475         }
476 }
477
478 static void pane_notify_close(struct pane *p safe)
479 {
480         while (!list_empty(&p->notifiees)) {
481                 struct notifier *n = list_first_entry(&p->notifiees,
482                                                       struct notifier,
483                                                       notifier_link);
484                 list_del_init(&n->notifiee_link);
485                 list_del_init(&n->notifier_link);
486                 if (strcmp(n->notification, "Notify:Close") == 0)
487                         pane_call(n->notifiee, n->notification, p);
488                 /* Close:Notify can be delivered even to DAMAGED_CLOSED
489                  * panes
490                  */
491                 if (strcmp(n->notification, "Close:Notify") == 0)
492                         pane_call(n->notifiee, n->notification, p);
493                 free(n->notification);
494                 free(n);
495         }
496 }
497
498 int do_pane_notify(struct pane *home, const char *notification safe,
499                    struct pane *p safe,
500                    int num, struct mark *m, const char *str,
501                    int num2, struct mark *m2, const char *str2,
502                    struct command *comm2)
503 {
504         /* Return the largest absolute return value. If no notifiees are found.
505          * return 0
506          */
507         int ret = 0;
508         int cnt = 0;
509         struct notifier *n, *n2;
510
511         if (!home)
512                 home = p;
513         list_for_each_entry_reverse(n, &home->notifiees, notifier_link)
514                 if (strcmp(n->notification, notification) == 0 &&
515                     n->noted) {
516                         /* Nested notifications are not allowed. We cannot
517                          * be sure the outer notification is sent, and it might
518                          * contain different information.
519                          */
520                         LOG("Nested notification from %s to %s for %s not permitted.",
521                             home->name, n->notifiee->name, notification);
522                         LOG_BT();
523                         return Efail;
524                 }
525 restart:
526         list_for_each_entry(n, &home->notifiees, notifier_link) {
527                 if (n->noted)
528                         continue;
529                 if (strcmp(n->notification, notification) == 0) {
530                         int r;
531                         n->noted = 2;
532                         r = pane_call(n->notifiee, notification, p,
533                                       num, m, str,
534                                       num2, m2, str2, cnt,ret, comm2);
535                         if (abs(r) > abs(ret))
536                                 ret = r;
537                         cnt += 1;
538                         /* Panes might have been closed or notifications removed
539                          * so nothing can be trusted... except this home pane
540                          * had better still exist.
541                          */
542                         list_for_each_entry(n2, &home->notifiees, notifier_link)
543                                 if (n2 == n && n->noted == 2) {
544                                         /* Still safe .. */
545                                         n->noted = 1;
546                                         continue;
547                                 }
548                         /* 'n' has been removed, restart */
549                         goto restart;
550                 }
551         }
552         list_for_each_entry(n, &home->notifiees, notifier_link)
553                 if (strcmp(n->notification, notification) == 0)
554                         n->noted = 0;
555         return ret;
556 }
557
558 static void pane_refocus(struct pane *p safe)
559 {
560         struct pane *c;
561         struct mark *pt;
562
563         p->focus = NULL;
564         /* choose the worst credible focus - the oldest.
565          * Really some one else should be updating the focus, this is
566          * just a fall-back
567          */
568         list_for_each_entry_reverse(c, &p->children, siblings)
569                 if (c->z >= 0) {
570                         p->focus = c;
571                         break;
572                 }
573         /* Tell the new focus to update - probably just a cursor update */
574         p = pane_leaf(p);
575         pt = call_ret(mark, "doc:point", p);
576         call("view:changed", p, 0, pt);
577 }
578
579 void pane_close(struct pane *p safe)
580 {
581         struct pane *c;
582         struct pane *ed;
583         bool infocus;
584         bool again;
585
586         if (p->damaged & DAMAGED_CLOSED)
587                 return;
588         p->damaged |= DAMAGED_CLOSED;
589         pane_check(p);
590
591         ed = pane_root(p);
592
593         /* Lots of panes might need to be notified of our closing.
594          * We try to notify the more "distant" first, so children are
595          * last and those registered for notification are first.
596          * Parent comes beween.
597          */
598         pane_notify_close(p);
599
600         if (!(p->parent->damaged & DAMAGED_CLOSED))
601                 pane_call(p->parent, "Child-Notify", p, -1);
602         list_del_init(&p->siblings);
603
604         do {
605                 again = False;
606                 list_for_each_entry(c, &p->children, siblings) {
607                         if (c->damaged & DAMAGED_CLOSED)
608                                 continue;
609                         pane_close(c);
610                         again = True;
611                         break;
612                 }
613         } while (again);
614
615         /* It is important not to drop notifiers until after all dependant
616          * panes are closed, as their closing might send a notification back
617          * to this pane.  That happens with documents when the holder of
618          * a mark-view is closed.
619          */
620         pane_drop_notifiers(p, NULL);
621
622         infocus = pane_has_focus(p);
623         if (!(p->parent->damaged & DAMAGED_CLOSED) &&
624             p->parent->focus == p)
625                 pane_refocus(p->parent);
626
627         if (!(p->damaged & DAMAGED_NOINIT))
628                 pane_call(p, "Close", p, infocus);
629
630         /* If a child has not yet had "Close" called, we need to leave
631          * ->parent in place so a full range of commands are available.
632          */
633         p->damaged |= DAMAGED_DEAD;
634         if (ed != p) {
635                 editor_delayed_free(ed, p);
636         } else {
637                 command_put(p->handle);
638                 p->handle = NULL;
639                 attr_free(&p->attrs);
640                 pane_put(p);
641         }
642 }
643
644 void pane_free(struct pane *p safe)
645 {
646         if (p->refs == 0)
647                 unalloc_buf_safe(p, p->alloc_size, pane);
648 }
649
650 bool pane_resize(struct pane *p safe, int x, int y, int w, int h)
651 {
652         int damage = 0;
653
654         if (p->x != x || p->y != y) {
655                 damage |= DAMAGED_SIZE;
656                 p->x = x;
657                 p->y = y;
658         }
659         if (w >= 0 &&
660             (p->w != w || p->h != h)) {
661                 damage |= DAMAGED_SIZE;
662                 p->w = w;
663                 p->h = h;
664         }
665         if (p->w < 0 || p->h < 0) {
666                 if (p->w < 0)
667                         p->w = 0;
668                 if (p->h < 0)
669                         p->h = 0;
670         }
671         /* tell the pane to resize its children later */
672         pane_damaged(p, damage);
673         if (damage)
674                 pane_notify("Notify:resize", p);
675         return !!damage;
676 }
677
678 void pane_reparent(struct pane *p safe, struct pane *newparent safe)
679 {
680         /* Change the parent of 'p' to be 'newparent.
681          * An important consideration is that a pane must never move up the
682          * hierarchy (towards the root), but only sideways or down.  This ensures
683          * that any mark the pane (or a descendant thereof) might hold still gets
684          * delivered to the correct document.  There is one exception that a pane
685          * that was newly created may be re-attached above some ancestors.
686          * There is not currently any test for "newness" though that may be added
687          * later (FIXME)
688          *
689          * 'newparent' must be a descendant of p->parent.
690          * If it is a sibling of p or descentant thereof, p is simply detached from
691          * its parent and reattached below newparent.
692          * If it is a descendant of p (it cannot be p itself), then as well as p
693          * being detached from it parent and attached to newparent, newparent is detached
694          * and attached between p and p->parent, thus ensuring no loop is created.
695          */
696         int replaced = 0;
697         struct pane *pc = pane_my_child(p->parent, newparent);
698         if (pc == NULL || newparent == p) {
699                 LOG("Cannot reparent %s to %s, new parent must be a sibling or their descendant",
700                     p->name, newparent->name);
701                 LOG_BT();
702                 return;
703         }
704         /* Detatch p */
705         list_del_init(&p->siblings);
706         if (p->parent->focus == p)
707                 p->parent->focus = pc;
708         if (pc == p) {
709                 p->parent->focus = NULL;
710                 /* newparent is below p, need to detach and reattach it */
711                 if (newparent->parent->focus == newparent)
712                         newparent->parent->focus = NULL;
713                 pane_call(newparent->parent, "Child-Notify", newparent, -2);
714                 newparent->parent = p->parent;
715                 list_move(&newparent->siblings, &p->parent->children);
716                 pane_resize(newparent, 0, 0, p->parent->w, p->parent->h);
717                 replaced = 1;
718         }
719         pane_call(p->parent, "Child-Notify", p, -2);
720         /* Reattach p under newparent */
721         p->parent = newparent;
722         newparent->damaged |= p->damaged;
723         if (newparent->focus == NULL)
724                 newparent->focus = p;
725         list_add(&p->siblings, &newparent->children);
726         pane_call(p->parent, "Child-Notify", p, 2);
727         if (replaced)
728                 pane_call(newparent->parent, "Child-Notify", newparent, 2);
729 }
730
731 void pane_move_after(struct pane *p safe, struct pane *after)
732 {
733         /* Move 'p' after 'after', or if !after, move to start */
734         if (p == p->parent || p == after)
735                 return;
736         if (after) {
737                 if (p->parent != after->parent)
738                         return;
739                 list_move(&p->siblings, &after->siblings);
740         } else {
741                 list_move(&p->siblings, &p->parent->children);
742         }
743 }
744
745 void pane_subsume(struct pane *p safe, struct pane *parent safe)
746 {
747         /* move all content from p into parent, which must be empty,
748          * except possibly for 'p'.
749          * 'data' and 'handle' are swapped.
750          * Finally, p is freed
751          */
752         void *data;
753         struct command *handle;
754         struct pane *c;
755
756         list_del_init(&p->siblings);
757         if (p->parent->focus == p)
758                 pane_refocus(p->parent);
759
760         p->parent = pane_root(parent);
761         while (!list_empty(&p->children)) {
762                 c = list_first_entry(&p->children, struct pane, siblings);
763                 list_move(&c->siblings, &parent->children);
764                 c->parent = parent;
765                 parent->damaged |= c->damaged;
766         }
767         parent->focus = p->focus;
768
769         handle = parent->handle;
770         parent->handle = p->handle;
771         p->handle = handle;
772
773         data = parent->data;
774         parent->data = p->data;
775         p->data = data;
776
777         parent->damaged |= p->damaged;
778         pane_damaged(p, DAMAGED_SIZE);
779
780         pane_close(p);
781 }
782
783 void pane_focus(struct pane *focus)
784 {
785         struct pane *p = focus;
786         struct mark *pt;
787         if (!p)
788                 return;
789         /* refocus up to the display, but not to the root */
790         /* We have root->input->display. FIXME I need a better way
791          * to detect the 'display' level.
792          */
793         for (; p->parent->parent->parent != p->parent->parent; p = p->parent) {
794                 struct pane *old = p->parent->focus;
795                 if (old == p)
796                         continue;
797                 p->parent->focus = p;
798                 if (old) {
799                         old = pane_leaf(old);
800                         pt = call_ret(mark, "doc:point", old);
801                         call("view:changed", old, 0, pt);
802                         home_call(old, "pane:defocus", focus);
803                 }
804         }
805         pt = call_ret(mark, "doc:point", pane_leaf(focus));
806         call("view:changed", pane_leaf(focus), 0, pt);
807         call("pane:refocus", focus);
808 }
809
810 bool do_pane_has_focus(struct pane *focus, struct pane *root)
811 {
812         /* Would pane_focus change anything */
813         struct pane *p = focus;
814
815         if (!p)
816                 return False;
817         /* We check down to the declared root, or to on1 above
818          * the global root.  Where the focus of the global root
819          * is never matters.
820          */
821         for (;
822              p != root
823              && p->parent->parent->parent != p->parent->parent;
824              p = p->parent)
825                 if (p->parent->focus != p)
826                         return False;
827         return True;
828 }
829
830 char *pane_attr_get(struct pane *p, const char *key safe)
831 {
832         while (p) {
833                 char *a = attr_find(p->attrs, key);
834
835                 if (a)
836                         return a;
837                 a = CALL(strsave, pane, p, "get-attr", p, 0, NULL, key);
838                 if (a)
839                         return a;
840                 if (p == p->parent)
841                         return NULL;
842                 p = p->parent;
843         }
844         return NULL;
845 }
846
847 char *pane_mark_attr(struct pane *p safe, struct mark *m safe,
848                      const char *key safe)
849 {
850         return call_ret(strsave, "doc:get-attr", p, 0, m, key);
851 }
852
853 void pane_clone_children(struct pane *from, struct pane *to)
854 {
855         /* "to" is a clone of "from", but has no children or attributes.
856          * Copy the attributes and
857          * clone all the children of "from" to "to"
858          * Ignore z>0 children
859          */
860         struct pane *c;
861
862         if (!from || !to)
863                 return;
864         if (from->attrs && !to->attrs)
865                 to->attrs = attr_copy(from->attrs);
866         list_for_each_entry(c, &from->children, siblings)
867                 c->damaged |= DAMAGED_NOT_HANDLED;
868 restart:
869         list_for_each_entry(c, &from->children, siblings) {
870                 if (c->damaged & DAMAGED_NOT_HANDLED)
871                         c->damaged &= ~DAMAGED_NOT_HANDLED;
872                 else
873                         /* Only handle each pane once */
874                         continue;
875                 if (c->z > 0)
876                         continue;
877                 pane_call(c, "Clone", to);
878                 goto restart;
879         }
880 }
881
882 struct pane *pane_my_child(struct pane *p, struct pane *c)
883 {
884         while (c && c->parent != p) {
885                 if (c->parent == c)
886                         return NULL;
887                 c = c->parent;
888         }
889         return c;
890 }
891
892 DEF_CB(take_simple)
893 {
894         struct call_return *cr = container_of(ci->comm, struct call_return, c);
895         cr->p = ci->focus;
896         cr->m = ci->mark;
897         cr->m2 = ci->mark2;
898         cr->i = ci->num;
899         cr->i2 = ci->num2;
900         cr->x = ci->x;
901         cr->y = ci->y;
902         cr->comm = ci->comm2;
903         cr->s = strsave(ci->focus, ci->str);
904         return 1;
905 }
906
907 DEF_CB(take_str)
908 {
909         struct call_return *cr = container_of(ci->comm, struct call_return, c);
910
911         if (!ci->str)
912                 return Enoarg;
913         cr->s = strdup(ci->str);
914         return 1;
915 }
916
917 DEF_CB(take_comm)
918 {
919         struct call_return *cr = container_of(ci->comm, struct call_return, c);
920         if (ci->comm2)
921                 cr->comm = command_get(ci->comm2);
922         return 1;
923 }
924
925 DEF_CMD(take_bytes)
926 {
927         struct call_return *cr = container_of(ci->comm, struct call_return, c);
928
929         if (!ci->str || ci->num < 0 || ci->num > 1000*1000*1000)
930                 return Enoarg;
931         cr->s = malloc(ci->num);
932         cr->i = ci->num;
933         if (cr->s)
934                 memcpy(cr->s, ci->str, ci->num);
935         return 1;
936 }
937
938 struct pane *do_call_pane(enum target_type type, struct pane *home,
939                           struct command *comm2a,
940                           const char *key safe, struct pane *focus safe,
941                           int num,  struct mark *m,  const char *str,
942                           int num2, struct mark *m2, const char *str2,
943                           int x, int y, struct command *comm2b)
944 {
945         struct call_return cr = {};
946
947         cr.c = take_simple;
948         cr.ret = do_call_val(type, home, comm2a, key, focus, num, m, str,
949                              num2, m2, str2, x, y, &cr.c);
950         if (cr.ret < 0)
951                 return NULL;
952         return cr.p;
953 }
954
955 struct mark *do_call_mark(enum target_type type, struct pane *home,
956                           struct command *comm2a,
957                           const char *key safe, struct pane *focus safe,
958                           int num,  struct mark *m,  const char *str,
959                           int num2, struct mark *m2, const char *str2,
960                           int x, int y, struct command *comm2b)
961 {
962         struct call_return cr = {};
963
964         cr.c = take_simple;
965         cr.ret = do_call_val(type, home, comm2a, key, focus, num, m, str,
966                              num2, m2, str2, x, y, &cr.c);
967         if (cr.ret < 0)
968                 return NULL;
969         return cr.m;
970 }
971
972 struct mark *do_call_mark2(enum target_type type, struct pane *home,
973                            struct command *comm2a,
974                            const char *key safe, struct pane *focus safe,
975                            int num,  struct mark *m,  const char *str,
976                            int num2, struct mark *m2, const char *str2,
977                            int x, int y, struct command *comm2b)
978 {
979         struct call_return cr = {};
980
981         cr.c = take_simple;
982         cr.ret = do_call_val(type, home, comm2a, key, focus, num, m, str,
983                              num2, m2, str2, x, y, &cr.c);
984         if (cr.ret < 0)
985                 return NULL;
986         return cr.m2;
987 }
988
989 struct command *do_call_comm(enum target_type type, struct pane *home,
990                              struct command *comm2a,
991                              const char *key safe, struct pane *focus safe,
992                              int num,  struct mark *m,  const char *str,
993                              int num2, struct mark *m2, const char *str2,
994                              int x, int y, struct command *comm2b)
995 {
996         struct call_return cr = {};
997
998         cr.c = take_comm;
999         cr.ret = do_call_val(type, home, comm2a, key, focus, num, m, str,
1000                              num2, m2, str2, x, y, &cr.c);
1001         if (cr.ret < 0)
1002                 return NULL;
1003         return cr.comm;
1004 }
1005
1006 char *do_call_strsave(enum target_type type, struct pane *home,
1007                       struct command *comm2a,
1008                       const char *key safe, struct pane *focus safe,
1009                       int num,  struct mark *m,  const char *str,
1010                       int num2, struct mark *m2, const char *str2,
1011                       int x, int y, struct command *comm2b)
1012 {
1013         struct call_return cr = {};
1014
1015         cr.c = take_simple;
1016         cr.ret = do_call_val(type, home, comm2a, key, focus, num, m, str,
1017                              num2, m2, str2, x, y, &cr.c);
1018         return cr.s;
1019 }
1020
1021 struct call_return do_call_all(enum target_type type, struct pane *home,
1022                                struct command *comm2a,
1023                                const char *key safe, struct pane *focus safe,
1024                                int num,  struct mark *m,  const char *str,
1025                                int num2, struct mark *m2, const char *str2,
1026                                int x, int y, struct command *comm2b)
1027 {
1028         struct call_return cr = {};
1029
1030         cr.c = take_simple;
1031         cr.ret = do_call_val(type, home, comm2a, key, focus, num, m, str,
1032                              num2, m2, str2, x, y, &cr.c);
1033         return cr;
1034 }
1035
1036 char *do_call_str(enum target_type type, struct pane *home,
1037                   struct command *comm2a,
1038                   const char *key safe, struct pane *focus safe,
1039                   int num,  struct mark *m,  const char *str,
1040                   int num2, struct mark *m2, const char *str2,
1041                   int x, int y, struct command *comm2b)
1042 {
1043         struct call_return cr = {};
1044
1045         cr.c = take_str;
1046         cr.ret = do_call_val(type, home, comm2a, key, focus, num, m, str,
1047                              num2, m2, str2, x, y, &cr.c);
1048         if (cr.ret < 0) {
1049                 free(cr.s);
1050                 return NULL;
1051         }
1052         return cr.s;
1053 }
1054
1055 struct call_return do_call_bytes(enum target_type type, struct pane *home,
1056                                  struct command *comm2a,
1057                                  const char *key safe, struct pane *focus safe,
1058                                  int num,  struct mark *m,  const char *str,
1059                                  int num2, struct mark *m2, const char *str2,
1060                                  int x, int y, struct command *comm2b)
1061 {
1062         struct call_return cr = {};
1063
1064         cr.c = take_bytes;
1065         cr.ret = do_call_val(type, home, comm2a, key, focus, num, m, str,
1066                              num2, m2, str2, x, y, &cr.c);
1067         if (cr.ret < 0) {
1068                 free(cr.s);
1069                 cr.s = NULL;
1070         }
1071         return cr;
1072 }
1073
1074 struct xy pane_mapxy(struct pane *p safe, struct pane *target safe,
1075                      short x, short y, bool clip)
1076 {
1077         /* x and y are relative to p.  The result xy is relative to target */
1078         struct xy xy;
1079
1080         /* This is a bit of a hack, but is needed to map lib-renderline
1081          * co-ordes to a pane which is parallel with the render-line
1082          * pane, but might be further from the root.
1083          * We move 'target' towards the root to a pane of exactly the
1084          * same size and position.  This will not change a correct
1085          * result, and can make a correct result more likely.
1086          */
1087         while (target->parent != target &&
1088                target->x == 0 && target->y == 0 &&
1089                target->parent->w == target->w &&
1090                target->parent->h == target->h)
1091                 target = target->parent;
1092
1093         while (p != target && p != p->parent) {
1094                 if (clip && p->w > 0) {
1095                         if (x < 0)
1096                                 x = 0;
1097                         if (x > p->w)
1098                                 x = p->w;
1099                 }
1100                 if (clip && p->h > 0) {
1101                         if (y < 0)
1102                                 y = 0;
1103                         if (y > p->h)
1104                                 y = p->h;
1105                 }
1106                 x += p->x;
1107                 y += p->y;
1108                 p = p->parent;
1109         }
1110         xy.x = x;
1111         xy.y = y;
1112         return xy;
1113 }
1114
1115 struct xy pane_scale(struct pane *p safe)
1116 {
1117         /* "scale" is roughly pixels-per-point * 1000
1118          * So 10*scale.x/100 is the width of a typical character in default font.
1119          * 10*scale.y/100 is the height.
1120          * scale.x should be passed to Draw:text-size and and Draw:text to get
1121          * correctly sized text
1122          *
1123          * "scale:M" is provided by the display module and reports
1124          * the size of a captial M in default fond - width and height in pixels
1125          *
1126          */
1127         char *scM = pane_attr_get(p, "scale:M");
1128         char *sc;
1129         struct xy xy;
1130         int w,h;
1131         int mw, mh;
1132         int scale;
1133
1134         if (!scM ||
1135             sscanf(scM, "%dx%d", &mw, &mh) != 2 ||
1136             mw <= 0 || mh <= 0) {
1137                 /* Fonts have fixed 1x1 size so scaling not supported */
1138                 xy.x = 100;
1139                 xy.y = 100;
1140                 return xy;
1141         }
1142         /* "scale" is a request to change from the default.
1143          * It can be a simple number, in which case it is 1000 times a scale
1144          * factor, so "500" would be half of default size.
1145          * It can be an x,y pair, e.g. "800x240".
1146          * This chooses a scale so that the given number of points, (1/10 of
1147          * size of default "M") will fit in the pane.  If the pane is resized,
1148          * the scale will automatically adjust to fit the requested number
1149          * of characters.
1150          */
1151         sc = pane_attr_get(p, "scale");
1152         if (sc == NULL)
1153                 scale = 1000;
1154         else if (sscanf(sc, "%dx%d", &w, &h) == 2) {
1155                 /* choose scale so w,h point fits in pane */
1156                 int xscale, yscale;
1157                 if (w <= 0) w = 1;
1158                 if (h <= 0) h = 1;
1159                 xscale = 1000 * p->w * 10 / mw / w;
1160                 yscale = 1000 * p->h * 10 / mh / h;
1161                 scale = (xscale < yscale) ? xscale :  yscale;
1162         } else if (sscanf(sc, "%d", &scale) != 1)
1163                 scale = 1000;
1164
1165         if (scale < 10)
1166                 scale = 10;
1167         if (scale > 100000)
1168                 scale = 100000;
1169         xy.x = scale * mw / 10;
1170         xy.y = scale * mh / 10;
1171         return xy;
1172 }
1173
1174 static inline unsigned int ts_to_ms(struct timespec *ts safe)
1175 {
1176         return ts->tv_nsec / 1000 / 1000 + ts->tv_sec * 1000;
1177 }
1178
1179 bool pane_too_long(struct pane *p safe, unsigned int msec)
1180 {
1181         struct timespec ts;
1182         unsigned int duration;
1183
1184         if (p->timestamp == 0)
1185                 return False;
1186         if (p->timestamp == 1)
1187                 return True;
1188         clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);
1189         duration = ts_to_ms(&ts) - p->timestamp;
1190         if (msec < 100)
1191                 msec = 100;
1192         if (duration <= msec)
1193                 return False;
1194         /* If running under gdb, then I was probaly delayed
1195          * by single-stepping, so don't through an error
1196          */
1197         p->timestamp = ! debugger_is_present();
1198         return p->timestamp;
1199 }
1200
1201 void pane_set_time(struct pane *p safe)
1202 {
1203         struct timespec ts;
1204
1205         clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);
1206         p->timestamp = ts_to_ms(&ts);
1207         if (p->timestamp <= 1)
1208                 p->timestamp = 2;
1209 }