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