2 * Copyright Neil Brown ©2023 <neil@brown.name>
3 * May be distributed under terms of GPLv2 - see file:COPYING
5 * Core per-window functionality.
7 * Provide a pane that is instantiated between the root and any window
8 * stack, to provide common functionality. These includes:
10 * - setting per-window attributes
11 * - registering and forwarding per-window notifications
12 * - Being an intermediary for per-window selections.
14 * ==============================================================
15 * Allow any pane to "claim ownership" of "the selection", or to
16 * "commit" the selection. A pane can also "discard" the selection,
17 * but that only works if the pane owns it.
19 * This can be used for mouse-based copy/paste and interaction with the
20 * X11 "PRIMARY" clipboard.
21 * When a selection is made in any pane it claims "the selection".
22 * When a mouse-based paste request is made, the receiving pane can ask for
23 * the selection to be "commited", and then access the most recent copy-buffer.
24 * The owner of a selection will, if the selection is still valid, call
25 * copy:save to save the selected content.
26 * When a "paste" request is made where the location is based on the "point"
27 * (current cursor) it is unlikely that a selection in the same pane should be
28 * used - if there is one it is more likely to be intended to receive the paste.
29 * So the target pane can first "discard" the selection, then "commit", then call
30 * "copy:get". If the selection is in this pane, the "discard" will succeed,
31 * the "commit" will be a no-op, and the top copy buf will be used.
32 * If the selection is in another pane (or another app via X11), the "discard"
33 * will fail (wrong owner), the "commit" will succeed and copy the selection,
34 * and the "copy:get" will get it.
36 * Operations are "selection:claim", "selection:commit" and "selection:discard".
37 * When the selection is claimed, the old owner gets called (not notified)
38 * "Notify:selection:claimed", and when a commit request is made,
39 * "Notify:selection:commit" is sent.
41 * A client can declare itself to be a fall-back handler by calling
42 * select:claim with num==1. Then if any other client discards its selection,
43 * the ownership reverse to the fallback. The fallback typically provides
44 * access to some selection external to edlib, such as the x11 selections.
52 #define PANE_DATA_TYPE struct window_data
57 struct pane *sel_owner;
59 struct pane *sel_owner_fallback;
61 #include "core-pane.h"
63 DEF_CMD(request_notify)
65 pane_add_notify(ci->focus, ci->home, ksuffix(ci, "window:request:"));
71 /* window:notify:... */
72 return home_pane_notify(ci->home, ksuffix(ci, "window:notify:"),
74 ci->num, ci->mark, ci->str,
75 ci->num2, ci->mark2, ci->str2, ci->comm2);
80 const char *val = ksuffix(ci, "window:set:");
88 attr_set_str(&ci->home->attrs, val, ci->str);
93 DEF_CMD(selection_claim)
95 struct window_data *wd = ci->home->data;
97 if (wd->sel_owner && wd->sel_owner != ci->focus) {
98 call("Notify:selection:claimed", wd->sel_owner);
99 //pane_drop_notifiers(ci->home, "Notify:Close", wd->sel_owner);
101 wd->sel_owner = ci->focus;
103 wd->sel_owner_fallback = ci->focus;
104 wd->sel_committed = 0;
105 pane_add_notify(ci->home, ci->focus, "Notify:Close");
109 DEF_CMD(selection_commit)
111 struct window_data *wd = ci->home->data;
113 if (wd->sel_owner && !wd->sel_committed) {
114 if (call("Notify:selection:commit", wd->sel_owner) != 2)
115 wd->sel_committed = 1;
120 DEF_CMD(selection_discard)
122 struct window_data *wd = ci->home->data;
123 struct pane *op, *fp;
127 if (wd->sel_owner_fallback == ci->focus)
128 wd->sel_owner_fallback = NULL;
129 /* Don't require exactly same pane for sel_owner,
130 * but ensure they have the same focus.
132 op = pane_leaf(wd->sel_owner);
133 fp = pane_leaf(ci->focus);
137 wd->sel_owner = wd->sel_owner_fallback;
138 wd->sel_committed = 0;
142 DEF_CMD(close_notify)
144 struct window_data *wd = ci->home->data;
146 if (wd->sel_owner_fallback == ci->focus)
147 wd->sel_owner_fallback = NULL;
149 if (wd->sel_owner == ci->focus)
150 wd->sel_owner = wd->sel_owner_fallback;
154 static struct map *window_map;
155 DEF_LOOKUP_CMD(window_handle, window_map);
157 DEF_CMD(window_attach)
161 p = pane_register(ci->focus, 0, &window_handle.c);
164 comm_call(ci->comm2, "cb", p);
168 DEF_CMD(window_close)
170 pane_close(ci->home);
174 void window_setup(struct pane *ed safe)
176 window_map = key_alloc();
178 key_add_prefix(window_map, "window:request:", &request_notify);
179 key_add_prefix(window_map, "window:notify:", &send_notify);
181 key_add(window_map, "Display:close", &window_close);
183 key_add_prefix(window_map, "window:set:", &window_set);
185 key_add(window_map, "selection:claim", &selection_claim);
186 key_add(window_map, "selection:commit", &selection_commit);
187 key_add(window_map, "selection:discard", &selection_discard);
188 key_add(window_map, "Notify:Close", &close_notify);
190 call_comm("global-set-command", ed, &window_attach, 0, NULL,
191 "attach-window-core");