Introduction
Introduction Statistics Contact Development Disclaimer Help
clipboard.c - ledit - Text editor (WIP)
git clone git://lumidify.org/ledit.git (fast, but not encrypted)
git clone https://lumidify.org/ledit.git (encrypted, but very slow)
git clone git://4kcetb7mo7hj6grozzybxtotsub5bempzo4lirzc3437amof2c2impyd.onion/…
Log
Files
Refs
README
LICENSE
---
clipboard.c (7329B)
---
1 #include <time.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5
6 #include <X11/Xlib.h>
7 #include <X11/Xatom.h>
8
9 #include "util.h"
10 #include "memory.h"
11 #include "common.h"
12 #include "clipboard.h"
13 #include "macros.h"
14 #include "config.h"
15 #include "ctrlsel.h"
16
17 /* Some *inspiration* taken from SDL (https://libsdl.org), mainly
18 the idea to create a separate window just for clipboard handling. */
19
20 static Window get_clipboard_window(ledit_clipboard *clip);
21 static Bool check_window(Display *dpy, XEvent *event, XPointer arg);
22 static txtbuf *get_text(ledit_clipboard *clip, int primary);
23
24 struct ledit_clipboard {
25 txtbuf *primary;
26 txtbuf *clipboard;
27 txtbuf *rbuf;
28 ledit_common *common;
29 Window window;
30 struct CtrlSelTarget starget;
31 struct CtrlSelTarget rtarget;
32 CtrlSelContext *scontext;
33 Atom xtarget;
34 };
35
36 ledit_clipboard *
37 clipboard_create(ledit_common *common) {
38 ledit_clipboard *clip = ledit_malloc(sizeof(ledit_clipboard));
39 clip->primary = txtbuf_new();
40 clip->clipboard = txtbuf_new();
41 clip->rbuf = txtbuf_new();
42 clip->common = common;
43 clip->window = None;
44 clip->xtarget = None;
45 #ifdef X_HAVE_UTF8_STRING
46 clip->xtarget = XInternAtom(common->dpy, "UTF8_STRING", False);
47 #else
48 clip->xtarget = XA_STRING;
49 #endif
50 clip->scontext = NULL;
51 return clip;
52 }
53
54 void
55 clipboard_destroy(ledit_clipboard *clip) {
56 txtbuf_destroy(clip->primary);
57 txtbuf_destroy(clip->clipboard);
58 txtbuf_destroy(clip->rbuf);
59 if (clip->scontext)
60 ctrlsel_disown(clip->scontext);
61 if (clip->window != None)
62 XDestroyWindow(clip->common->dpy, clip->window);
63 free(clip);
64 }
65
66 static Window
67 get_clipboard_window(ledit_clipboard *clip) {
68 if (clip->window == None) {
69 clip->window = XCreateWindow(
70 clip->common->dpy, DefaultRootWindow(clip->common->d…
71 -10, -10, 1, 1, 0, CopyFromParent, InputOnly, CopyFr…
72 );
73 XFlush(clip->common->dpy);
74 }
75 return clip->window;
76 }
77
78 void
79 clipboard_set_primary_text(ledit_clipboard *clip, char *text) {
80 txtbuf_set_text(clip->primary, text);
81 clipboard_set_primary_selection_owner(clip);
82 }
83
84 txtbuf *
85 clipboard_get_primary_buffer(ledit_clipboard *clip) {
86 return clip->primary;
87 }
88
89 void
90 clipboard_set_primary_selection_owner(ledit_clipboard *clip) {
91 Window window = get_clipboard_window(clip);
92 if (clip->scontext)
93 ctrlsel_disown(clip->scontext);
94 clip->scontext = NULL;
95 /* FIXME: is it fine to cast to unsigned char everywhere? */
96 ctrlsel_filltarget(clip->xtarget, clip->xtarget, 8, (unsigned ch…
97 /* FIXME: use proper time */
98 clip->scontext = ctrlsel_setowner(clip->common->dpy, window, XA_…
99 if (!clip->scontext)
100 fprintf(stderr, "WARNING: Could not own primary selectio…
101 }
102
103 void
104 clipboard_set_clipboard_text(ledit_clipboard *clip, char *text) {
105 txtbuf_set_text(clip->clipboard, text);
106 clipboard_set_clipboard_selection_owner(clip);
107 }
108
109 txtbuf *
110 clipboard_get_clipboard_buffer(ledit_clipboard *clip) {
111 return clip->clipboard;
112 }
113
114 void
115 clipboard_set_clipboard_selection_owner(ledit_clipboard *clip) {
116 Atom clip_atom;
117 Window window = get_clipboard_window(clip);
118 clip_atom = XInternAtom(clip->common->dpy, "CLIPBOARD", False);
119 if (clip->scontext)
120 ctrlsel_disown(clip->scontext);
121 clip->scontext = NULL;
122 /* FIXME: see clipboard_set_primary_selection_owner */
123 ctrlsel_filltarget(clip->xtarget, clip->xtarget, 8, (unsigned ch…
124 /* FIXME: use proper time */
125 clip->scontext = ctrlsel_setowner(clip->common->dpy, window, cli…
126 if (!clip->scontext)
127 fprintf(stderr, "WARNING: Could not own clipboard select…
128 }
129
130 void
131 clipboard_primary_to_clipboard(ledit_clipboard *clip) {
132 if (clip->primary->len > 0) {
133 txtbuf_copy(clip->clipboard, clip->primary);
134 clipboard_set_clipboard_selection_owner(clip);
135 }
136 }
137
138 int
139 clipboard_filter_event(ledit_clipboard *clip, XEvent *e) {
140 if (clip->window != None && e->xany.window == clip->window) {
141 if (clip->scontext)
142 ctrlsel_send(clip->scontext, e);
143 /* other events are discarded since there
144 was no request to get the clipboard text */
145 return 1;
146 }
147 return 0;
148 }
149
150 static Bool
151 check_window(Display *dpy, XEvent *event, XPointer arg) {
152 (void)dpy;
153 return *(Window *)arg == event->xany.window;
154 }
155
156 /* WARNING: The returned txtbuf needs to be copied before further proces…
157 static txtbuf *
158 get_text(ledit_clipboard *clip, int primary) {
159 CtrlSelContext *context;
160 Window window = get_clipboard_window(clip);
161 ctrlsel_filltarget(clip->xtarget, clip->xtarget, 0, NULL, 0, &cl…
162 Atom clip_atom = primary ? XA_PRIMARY : XInternAtom(clip->common…
163 /* FIXME: use proper time here */
164 context = ctrlsel_request(clip->common->dpy, window, clip_atom, …
165 /* FIXME: show error in window? */
166 if (!context) {
167 fprintf(stderr, "WARNING: Unable to request selection.\n…
168 return NULL;
169 }
170
171 struct timespec now, elapsed, last, start, sleep_time;
172 sleep_time.tv_sec = 0;
173 clock_gettime(CLOCK_MONOTONIC, &start);
174 last = start;
175 XEvent event;
176 while (1) {
177 /* FIXME: I have no idea how inefficient this is */
178 if (XCheckIfEvent(clip->common->dpy, &event, &check_wind…
179 switch (ctrlsel_receive(context, &event)) {
180 case CTRLSEL_RECEIVED:
181 goto done;
182 case CTRLSEL_ERROR:
183 fprintf(stderr, "WARNING: Could not get …
184 ctrlsel_cancel(context);
185 return NULL;
186 default:
187 continue;
188 }
189 }
190 clock_gettime(CLOCK_MONOTONIC, &now);
191 ledit_timespecsub(&now, &start, &elapsed);
192 /* Timeout if it takes too long. When that happens, beco…
193 avoid further timeouts in the future (I think I copie…
194 /* FIXME: configure timeout */
195 if (elapsed.tv_sec > 0) {
196 if (primary)
197 clipboard_set_primary_text(clip, "");
198 else
199 clipboard_set_clipboard_text(clip, "");
200 return NULL;
201 }
202 ledit_timespecsub(&now, &last, &elapsed);
203 if (elapsed.tv_sec == 0 && elapsed.tv_nsec < TICK) {
204 sleep_time.tv_nsec = TICK - elapsed.tv_nsec;
205 nanosleep(&sleep_time, NULL);
206 }
207 last = now;
208 }
209 return NULL;
210 done:
211 /* FIXME: this is a bit ugly because it fiddles around with txtb…
212 free(clip->rbuf->text);
213 clip->rbuf->cap = clip->rbuf->len = clip->rtarget.bufsize;
214 /* FIXME: again weird conversion between char and unsigned char …
215 clip->rbuf->text = (char *)clip->rtarget.buffer;
216 clip->rtarget.buffer = NULL; /* important so ctrlsel_cancel does…
217 ctrlsel_cancel(context);
218 return clip->rbuf;
219 }
220
221 txtbuf *
222 clipboard_get_clipboard_text(ledit_clipboard *clip) {
223 Atom clip_atom;
224 clip_atom = XInternAtom(clip->common->dpy, "CLIPBOARD", False);
225 Window window = get_clipboard_window(clip);
226 Window owner = XGetSelectionOwner(clip->common->dpy, clip_atom);
227 if (owner == None) {
228 return NULL;
229 } else if (owner == window) {
230 return clip->clipboard;
231 } else {
232 return get_text(clip, 0);
233 }
234 }
235
236 txtbuf *
237 clipboard_get_primary_text(ledit_clipboard *clip) {
238 Window window = get_clipboard_window(clip);
239 Window owner = XGetSelectionOwner(clip->common->dpy, XA_PRIMARY);
240 if (owner == None) {
241 return NULL;
242 } else if (owner == window) {
243 return clip->primary;
244 } else {
245 return get_text(clip, 1);
246 }
247 }
You are viewing proxied material from lumidify.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.