]> git.neil.brown.name Git - edlib.git/blob - core-pane.c
tile: don't use "Free", just "Close".
[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                 free(n->notification);
489                 free(n);
490         }
491 }
492
493 int do_pane_notify(struct pane *home, const char *notification safe,
494                    struct pane *p safe,
495                    int num, struct mark *m, const char *str,
496                    int num2, struct mark *m2, const char *str2,
497                    struct command *comm2)
498 {
499         /* Return the largest absolute return value. If no notifiees are found.
500          * return 0
501          */
502         int ret = 0;
503         int cnt = 0;
504         struct notifier *n, *n2;
505
506         if (!home)
507                 home = p;
508         list_for_each_entry_reverse(n, &home->notifiees, notifier_link)
509                 if (strcmp(n->notification, notification) == 0 &&
510                     n->noted) {
511                         /* Nested notifications are not allowed. We cannot
512                          * be sure the outer notification is sent, and it might
513                          * contain different information.
514                          */
515                         LOG("Nested notification from %s to %s for %s not permitted.",
516                             home->name, n->notifiee->name, notification);
517                         LOG_BT();
518                         return Efail;
519                 }
520 restart:
521         list_for_each_entry(n, &home->notifiees, notifier_link) {
522                 if (n->noted)
523                         continue;
524                 if (strcmp(n->notification, notification) == 0) {
525                         int r;
526                         n->noted = 2;
527                         r = pane_call(n->notifiee, notification, p,
528                                       num, m, str,
529                                       num2, m2, str2, cnt,ret, comm2);
530                         if (abs(r) > abs(ret))
531                                 ret = r;
532                         cnt += 1;
533                         /* Panes might have been closed or notifications removed
534                          * so nothing can be trusted... except this home pane
535                          * had better still exist.
536                          */
537                         list_for_each_entry(n2, &home->notifiees, notifier_link)
538                                 if (n2 == n && n->noted == 2) {
539                                         /* Still safe .. */
540                                         n->noted = 1;
541                                         continue;
542                                 }
543                         /* 'n' has been removed, restart */
544                         goto restart;
545                 }
546         }
547         list_for_each_entry(n, &home->notifiees, notifier_link)
548                 if (strcmp(n->notification, notification) == 0)
549                         n->noted = 0;
550         return ret;
551 }
552
553 static void pane_refocus(struct pane *p safe)
554 {
555         struct pane *c;
556         struct mark *pt;
557
558         p->focus = NULL;
559         /* choose the worst credible focus - the oldest.
560          * Really some one else should be updating the focus, this is
561          * just a fall-back
562          */
563         list_for_each_entry_reverse(c, &p->children, siblings)
564                 if (c->z >= 0) {
565                         p->focus = c;
566                         break;
567                 }
568         /* Tell the new focus to update - probably just a cursor update */
569         p = pane_leaf(p);
570         pt = call_ret(mark, "doc:point", p);
571         call("view:changed", p, 0, pt);
572 }
573
574 void pane_close(struct pane *p safe)
575 {
576         struct pane *c;
577         struct pane *ed;
578         bool infocus;
579         bool again;
580
581         if (p->damaged & DAMAGED_CLOSED)
582                 return;
583         p->damaged |= DAMAGED_CLOSED;
584         pane_check(p);
585
586         ed = pane_root(p);
587
588         /* Lots of panes might need to be notified of our closing.
589          * We try to notify the more "distant" first, so children are
590          * last and those registered for notification are first.
591          * Parent comes beween.
592          */
593         pane_notify_close(p);
594
595         if (!(p->parent->damaged & DAMAGED_CLOSED))
596                 pane_call(p->parent, "Child-Notify", p, -1);
597         list_del_init(&p->siblings);
598
599         do {
600                 again = False;
601                 list_for_each_entry(c, &p->children, siblings) {
602                         if (c->damaged & DAMAGED_CLOSED)
603                                 continue;
604                         pane_close(c);
605                         again = True;
606                         break;
607                 }
608         } while (again);
609
610         /* It is important not to drop notifiers until after all dependant
611          * panes are closed, as their closing might send a notification back
612          * to this pane.  That happens with documents when the holder of
613          * a mark-view is closed.
614          */
615         pane_drop_notifiers(p, NULL);
616
617         infocus = pane_has_focus(p);
618         if (!(p->parent->damaged & DAMAGED_CLOSED) &&
619             p->parent->focus == p)
620                 pane_refocus(p->parent);
621
622         if (!(p->damaged & DAMAGED_NOINIT))
623                 pane_call(p, "Close", p, infocus);
624
625         /* If a child has not yet had "Close" called, we need to leave
626          * ->parent in place so a full range of commands are available.
627          */
628         if (ed != p) {
629                 p->damaged |= DAMAGED_DEAD;
630                 editor_delayed_free(ed, p);
631         } else {
632                 pane_call(p, "Free", p);
633                 command_put(p->handle);
634                 p->handle = NULL;
635                 attr_free(&p->attrs);
636                 pane_put(p);
637         }
638 }
639
640 void pane_free(struct pane *p safe)
641 {
642         if (p->refs == 0)
643                 unalloc_buf_safe(p, p->alloc_size, pane);
644 }
645
646 bool pane_resize(struct pane *p safe, int x, int y, int w, int h)
647 {
648         int damage = 0;
649
650         if (p->x != x || p->y != y) {
651                 damage |= DAMAGED_SIZE;
652                 p->x = x;
653                 p->y = y;
654         }
655         if (w >= 0 &&
656             (p->w != w || p->h != h)) {
657                 damage |= DAMAGED_SIZE;
658                 p->w = w;
659                 p->h = h;
660         }
661         if (p->w < 0 || p->h < 0) {
662                 if (p->w < 0)
663                         p->w = 0;
664                 if (p->h < 0)
665                         p->h = 0;
666         }
667         /* tell the pane to resize its children later */
668         pane_damaged(p, damage);
669         if (damage)
670                 pane_notify("Notify:resize", p);
671         return !!damage;
672 }
673
674 void pane_reparent(struct pane *p safe, struct pane *newparent safe)
675 {
676         /* Change the parent of 'p' to be 'newparent.
677          * An important consideration is that a pane must never move up the
678          * hierarchy (towards the root), but only sideways or down.  This ensures
679          * that any mark the pane (or a descendant thereof) might hold still gets
680          * delivered to the correct document.  There is one exception that a pane
681          * that was newly created may be re-attached above some ancestors.
682          * There is not currently any test for "newness" though that may be added
683          * later (FIXME)
684          *
685          * 'newparent' must be a descendant of p->parent.
686          * If it is a sibling of p or descentant thereof, p is simply detached from
687          * its parent and reattached below newparent.
688          * If it is a descendant of p (it cannot be p itself), then as well as p
689          * being detached from it parent and attached to newparent, newparent is detached
690          * and attached between p and p->parent, thus ensuring no loop is created.
691          */
692         int replaced = 0;
693         struct pane *pc = pane_my_child(p->parent, newparent);
694         if (pc == NULL || newparent == p) {
695                 LOG("Cannot reparent %s to %s, new parent must be a sibling or their descendant",
696                     p->name, newparent->name);
697                 LOG_BT();
698                 return;
699         }
700         /* Detatch p */
701         list_del_init(&p->siblings);
702         if (p->parent->focus == p)
703                 p->parent->focus = pc;
704         if (pc == p) {
705                 p->parent->focus = NULL;
706                 /* newparent is below p, need to detach and reattach it */
707                 if (newparent->parent->focus == newparent)
708                         newparent->parent->focus = NULL;
709                 pane_call(newparent->parent, "Child-Notify", newparent, -2);
710                 newparent->parent = p->parent;
711                 list_move(&newparent->siblings, &p->parent->children);
712                 pane_resize(newparent, 0, 0, p->parent->w, p->parent->h);
713                 replaced = 1;
714         }
715         pane_call(p->parent, "Child-Notify", p, -2);
716         /* Reattach p under newparent */
717         p->parent = newparent;
718         newparent->damaged |= p->damaged;
719         if (newparent->focus == NULL)
720                 newparent->focus = p;
721         list_add(&p->siblings, &newparent->children);
722         pane_call(p->parent, "Child-Notify", p, 2);
723         if (replaced)
724                 pane_call(newparent->parent, "Child-Notify", newparent, 2);
725 }
726
727 void pane_move_after(struct pane *p safe, struct pane *after)
728 {
729         /* Move 'p' after 'after', or if !after, move to start */
730         if (p == p->parent || p == after)
731                 return;
732         if (after) {
733                 if (p->parent != after->parent)
734                         return;
735                 list_move(&p->siblings, &after->siblings);
736         } else {
737                 list_move(&p->siblings, &p->parent->children);
738         }
739 }
740
741 void pane_subsume(struct pane *p safe, struct pane *parent safe)
742 {
743         /* move all content from p into parent, which must be empty,
744          * except possibly for 'p'.
745          * 'data' and 'handle' are swapped.
746          * Finally, p is freed
747          */
748         void *data;
749         struct command *handle;
750         struct pane *c;
751
752         list_del_init(&p->siblings);
753         if (p->parent->focus == p)
754                 pane_refocus(p->parent);
755
756         p->parent = pane_root(parent);
757         while (!list_empty(&p->children)) {
758                 c = list_first_entry(&p->children, struct pane, siblings);
759                 list_move(&c->siblings, &parent->children);
760                 c->parent = parent;
761                 parent->damaged |= c->damaged;
762         }
763         parent->focus = p->focus;
764
765         handle = parent->handle;
766         parent->handle = p->handle;
767         p->handle = handle;
768
769         data = parent->data;
770         parent->data = p->data;
771         p->data = data;
772
773         parent->damaged |= p->damaged;
774         pane_damaged(p, DAMAGED_SIZE);
775
776         pane_close(p);
777 }
778
779 void pane_focus(struct pane *focus)
780 {
781         struct pane *p = focus;
782         struct mark *pt;
783         if (!p)
784                 return;
785         /* refocus up to the display, but not to the root */
786         /* We have root->input->display. FIXME I need a better way
787          * to detect the 'display' level.
788          */
789         for (; p->parent->parent->parent != p->parent->parent; p = p->parent) {
790                 struct pane *old = p->parent->focus;
791                 if (old == p)
792                         continue;
793                 p->parent->focus = p;
794                 if (old) {
795                         old = pane_leaf(old);
796                         pt = call_ret(mark, "doc:point", old);
797                         call("view:changed", old, 0, pt);
798                         home_call(old, "pane:defocus", focus);
799                 }
800         }
801         pt = call_ret(mark, "doc:point", pane_leaf(focus));
802         call("view:changed", pane_leaf(focus), 0, pt);
803         call("pane:refocus", focus);
804 }
805
806 bool do_pane_has_focus(struct pane *focus, struct pane *root)
807 {
808         /* Would pane_focus change anything */
809         struct pane *p = focus;
810
811         if (!p)
812                 return False;
813         /* We check down to the declared root, or to on1 above
814          * the global root.  Where the focus of the global root
815          * is never matters.
816          */
817         for (;
818              p != root
819              && p->parent->parent->parent != p->parent->parent;
820              p = p->parent)
821                 if (p->parent->focus != p)
822                         return False;
823         return True;
824 }
825
826 char *pane_attr_get(struct pane *p, const char *key safe)
827 {
828         while (p) {
829                 char *a = attr_find(p->attrs, key);
830
831                 if (a)
832                         return a;
833                 a = CALL(strsave, pane, p, "get-attr", p, 0, NULL, key);
834                 if (a)
835                         return a;
836                 if (p == p->parent)
837                         return NULL;
838                 p = p->parent;
839         }
840         return NULL;
841 }
842
843 char *pane_mark_attr(struct pane *p safe, struct mark *m safe,
844                      const char *key safe)
845 {
846         return call_ret(strsave, "doc:get-attr", p, 0, m, key);
847 }
848
849 void pane_clone_children(struct pane *from, struct pane *to)
850 {
851         /* "to" is a clone of "from", but has no children or attributes.
852          * Copy the attributes and
853          * clone all the children of "from" to "to"
854          * Ignore z>0 children
855          */
856         struct pane *c;
857
858         if (!from || !to)
859                 return;
860         if (from->attrs && !to->attrs)
861                 to->attrs = attr_copy(from->attrs);
862         list_for_each_entry(c, &from->children, siblings)
863                 c->damaged |= DAMAGED_NOT_HANDLED;
864 restart:
865         list_for_each_entry(c, &from->children, siblings) {
866                 if (c->damaged & DAMAGED_NOT_HANDLED)
867                         c->damaged &= ~DAMAGED_NOT_HANDLED;
868                 else
869                         /* Only handle each pane once */
870                         continue;
871                 if (c->z > 0)
872                         continue;
873                 pane_call(c, "Clone", to);
874                 goto restart;
875         }
876 }
877
878 struct pane *pane_my_child(struct pane *p, struct pane *c)
879 {
880         while (c && c->parent != p) {
881                 if (c->parent == c)
882                         return NULL;
883                 c = c->parent;
884         }
885         return c;
886 }
887
888 DEF_CB(take_simple)
889 {
890         struct call_return *cr = container_of(ci->comm, struct call_return, c);
891         cr->p = ci->focus;
892         cr->m = ci->mark;
893         cr->m2 = ci->mark2;
894         cr->i = ci->num;
895         cr->i2 = ci->num2;
896         cr->x = ci->x;
897         cr->y = ci->y;
898         cr->comm = ci->comm2;
899         cr->s = strsave(ci->focus, ci->str);
900         return 1;
901 }
902
903 DEF_CB(take_str)
904 {
905         struct call_return *cr = container_of(ci->comm, struct call_return, c);
906
907         if (!ci->str)
908                 return Enoarg;
909         cr->s = strdup(ci->str);
910         return 1;
911 }
912
913 DEF_CB(take_comm)
914 {
915         struct call_return *cr = container_of(ci->comm, struct call_return, c);
916         if (ci->comm2)
917                 cr->comm = command_get(ci->comm2);
918         return 1;
919 }
920
921 DEF_CMD(take_bytes)
922 {
923         struct call_return *cr = container_of(ci->comm, struct call_return, c);
924
925         if (!ci->str || ci->num < 0 || ci->num > 1000*1000*1000)
926                 return Enoarg;
927         cr->s = malloc(ci->num);
928         cr->i = ci->num;
929         if (cr->s)
930                 memcpy(cr->s, ci->str, ci->num);
931         return 1;
932 }
933
934 struct pane *do_call_pane(enum target_type type, struct pane *home,
935                           struct command *comm2a,
936                           const char *key safe, struct pane *focus safe,
937                           int num,  struct mark *m,  const char *str,
938                           int num2, struct mark *m2, const char *str2,
939                           int x, int y, struct command *comm2b)
940 {
941         struct call_return cr = {};
942
943         cr.c = take_simple;
944         cr.ret = do_call_val(type, home, comm2a, key, focus, num, m, str,
945                              num2, m2, str2, x, y, &cr.c);
946         if (cr.ret < 0)
947                 return NULL;
948         return cr.p;
949 }
950
951 struct mark *do_call_mark(enum target_type type, struct pane *home,
952                           struct command *comm2a,
953                           const char *key safe, struct pane *focus safe,
954                           int num,  struct mark *m,  const char *str,
955                           int num2, struct mark *m2, const char *str2,
956                           int x, int y, struct command *comm2b)
957 {
958         struct call_return cr = {};
959
960         cr.c = take_simple;
961         cr.ret = do_call_val(type, home, comm2a, key, focus, num, m, str,
962                              num2, m2, str2, x, y, &cr.c);
963         if (cr.ret < 0)
964                 return NULL;
965         return cr.m;
966 }
967
968 struct mark *do_call_mark2(enum target_type type, struct pane *home,
969                            struct command *comm2a,
970                            const char *key safe, struct pane *focus safe,
971                            int num,  struct mark *m,  const char *str,
972                            int num2, struct mark *m2, const char *str2,
973                            int x, int y, struct command *comm2b)
974 {
975         struct call_return cr = {};
976
977         cr.c = take_simple;
978         cr.ret = do_call_val(type, home, comm2a, key, focus, num, m, str,
979                              num2, m2, str2, x, y, &cr.c);
980         if (cr.ret < 0)
981                 return NULL;
982         return cr.m2;
983 }
984
985 struct command *do_call_comm(enum target_type type, struct pane *home,
986                              struct command *comm2a,
987                              const char *key safe, struct pane *focus safe,
988                              int num,  struct mark *m,  const char *str,
989                              int num2, struct mark *m2, const char *str2,
990                              int x, int y, struct command *comm2b)
991 {
992         struct call_return cr = {};
993
994         cr.c = take_comm;
995         cr.ret = do_call_val(type, home, comm2a, key, focus, num, m, str,
996                              num2, m2, str2, x, y, &cr.c);
997         if (cr.ret < 0)
998                 return NULL;
999         return cr.comm;
1000 }
1001
1002 char *do_call_strsave(enum target_type type, struct pane *home,
1003                       struct command *comm2a,
1004                       const char *key safe, struct pane *focus safe,
1005                       int num,  struct mark *m,  const char *str,
1006                       int num2, struct mark *m2, const char *str2,
1007                       int x, int y, struct command *comm2b)
1008 {
1009         struct call_return cr = {};
1010
1011         cr.c = take_simple;
1012         cr.ret = do_call_val(type, home, comm2a, key, focus, num, m, str,
1013                              num2, m2, str2, x, y, &cr.c);
1014         return cr.s;
1015 }
1016
1017 struct call_return do_call_all(enum target_type type, struct pane *home,
1018                                struct command *comm2a,
1019                                const char *key safe, struct pane *focus safe,
1020                                int num,  struct mark *m,  const char *str,
1021                                int num2, struct mark *m2, const char *str2,
1022                                int x, int y, struct command *comm2b)
1023 {
1024         struct call_return cr = {};
1025
1026         cr.c = take_simple;
1027         cr.ret = do_call_val(type, home, comm2a, key, focus, num, m, str,
1028                              num2, m2, str2, x, y, &cr.c);
1029         return cr;
1030 }
1031
1032 char *do_call_str(enum target_type type, struct pane *home,
1033                   struct command *comm2a,
1034                   const char *key safe, struct pane *focus safe,
1035                   int num,  struct mark *m,  const char *str,
1036                   int num2, struct mark *m2, const char *str2,
1037                   int x, int y, struct command *comm2b)
1038 {
1039         struct call_return cr = {};
1040
1041         cr.c = take_str;
1042         cr.ret = do_call_val(type, home, comm2a, key, focus, num, m, str,
1043                              num2, m2, str2, x, y, &cr.c);
1044         if (cr.ret < 0) {
1045                 free(cr.s);
1046                 return NULL;
1047         }
1048         return cr.s;
1049 }
1050
1051 struct call_return do_call_bytes(enum target_type type, struct pane *home,
1052                                  struct command *comm2a,
1053                                  const char *key safe, struct pane *focus safe,
1054                                  int num,  struct mark *m,  const char *str,
1055                                  int num2, struct mark *m2, const char *str2,
1056                                  int x, int y, struct command *comm2b)
1057 {
1058         struct call_return cr = {};
1059
1060         cr.c = take_bytes;
1061         cr.ret = do_call_val(type, home, comm2a, key, focus, num, m, str,
1062                              num2, m2, str2, x, y, &cr.c);
1063         if (cr.ret < 0) {
1064                 free(cr.s);
1065                 cr.s = NULL;
1066         }
1067         return cr;
1068 }
1069
1070 struct xy pane_mapxy(struct pane *p safe, struct pane *target safe,
1071                      short x, short y, bool clip)
1072 {
1073         /* x and y are relative to p.  The result xy is relative to target */
1074         struct xy xy;
1075
1076         /* This is a bit of a hack, but is needed to map lib-renderline
1077          * co-ordes to a pane which is parallel with the render-line
1078          * pane, but might be further from the root.
1079          * We move 'target' towards the root to a pane of exactly the
1080          * same size and position.  This will not change a correct
1081          * result, and can make a correct result more likely.
1082          */
1083         while (target->parent != target &&
1084                target->x == 0 && target->y == 0 &&
1085                target->parent->w == target->w &&
1086                target->parent->h == target->h)
1087                 target = target->parent;
1088
1089         while (p != target && p != p->parent) {
1090                 if (clip && p->w > 0) {
1091                         if (x < 0)
1092                                 x = 0;
1093                         if (x > p->w)
1094                                 x = p->w;
1095                 }
1096                 if (clip && p->h > 0) {
1097                         if (y < 0)
1098                                 y = 0;
1099                         if (y > p->h)
1100                                 y = p->h;
1101                 }
1102                 x += p->x;
1103                 y += p->y;
1104                 p = p->parent;
1105         }
1106         xy.x = x;
1107         xy.y = y;
1108         return xy;
1109 }
1110
1111 struct xy pane_scale(struct pane *p safe)
1112 {
1113         /* "scale" is roughly pixels-per-point * 1000
1114          * So 10*scale.x/100 is the width of a typical character in default font.
1115          * 10*scale.y/100 is the height.
1116          * scale.x should be passed to Draw:text-size and and Draw:text to get
1117          * correctly sized text
1118          *
1119          * "scale:M" is provided by the display module and reports
1120          * the size of a captial M in default fond - width and height in pixels
1121          *
1122          */
1123         char *scM = pane_attr_get(p, "scale:M");
1124         char *sc;
1125         struct xy xy;
1126         int w,h;
1127         int mw, mh;
1128         int scale;
1129
1130         if (!scM ||
1131             sscanf(scM, "%dx%d", &mw, &mh) != 2 ||
1132             mw <= 0 || mh <= 0) {
1133                 /* Fonts have fixed 1x1 size so scaling not supported */
1134                 xy.x = 100;
1135                 xy.y = 100;
1136                 return xy;
1137         }
1138         /* "scale" is a request to change from the default.
1139          * It can be a simple number, in which case it is 1000 times a scale
1140          * factor, so "500" would be half of default size.
1141          * It can be an x,y pair, e.g. "800x240".
1142          * This chooses a scale so that the given number of points, (1/10 of
1143          * size of default "M") will fit in the pane.  If the pane is resized,
1144          * the scale will automatically adjust to fit the requested number
1145          * of characters.
1146          */
1147         sc = pane_attr_get(p, "scale");
1148         if (sc == NULL)
1149                 scale = 1000;
1150         else if (sscanf(sc, "%dx%d", &w, &h) == 2) {
1151                 /* choose scale so w,h point fits in pane */
1152                 int xscale, yscale;
1153                 if (w <= 0) w = 1;
1154                 if (h <= 0) h = 1;
1155                 xscale = 1000 * p->w * 10 / mw / w;
1156                 yscale = 1000 * p->h * 10 / mh / h;
1157                 scale = (xscale < yscale) ? xscale :  yscale;
1158         } else if (sscanf(sc, "%d", &scale) != 1)
1159                 scale = 1000;
1160
1161         if (scale < 10)
1162                 scale = 10;
1163         if (scale > 100000)
1164                 scale = 100000;
1165         xy.x = scale * mw / 10;
1166         xy.y = scale * mh / 10;
1167         return xy;
1168 }
1169
1170 static inline unsigned int ts_to_ms(struct timespec *ts safe)
1171 {
1172         return ts->tv_nsec / 1000 / 1000 + ts->tv_sec * 1000;
1173 }
1174
1175 bool pane_too_long(struct pane *p safe, unsigned int msec)
1176 {
1177         struct timespec ts;
1178         unsigned int duration;
1179
1180         if (p->timestamp == 0)
1181                 return False;
1182         if (p->timestamp == 1)
1183                 return True;
1184         clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);
1185         duration = ts_to_ms(&ts) - p->timestamp;
1186         if (msec < 100)
1187                 msec = 100;
1188         if (duration <= msec)
1189                 return False;
1190         /* If running under gdb, then I was probaly delayed
1191          * by single-stepping, so don't through an error
1192          */
1193         p->timestamp = ! debugger_is_present();
1194         return p->timestamp;
1195 }
1196
1197 void pane_set_time(struct pane *p safe)
1198 {
1199         struct timespec ts;
1200
1201         clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);
1202         p->timestamp = ts_to_ms(&ts);
1203         if (p->timestamp <= 1)
1204                 p->timestamp = 2;
1205 }