Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
ex_clipboard.c
Go to the documentation of this file.
1/*
2 * Nilorea Library
3 * Copyright (C) 2005-2026 Castagnier Mickael
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14 * implied. See the License for the specific language governing
15 * permissions and limitations under the License.
16 *
17 * SPDX-License-Identifier: Apache-2.0
18 */
19
29#include "nilorea/n_clipboard.h"
30#include "nilorea/n_log.h"
31
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35
36static int failures = 0;
37#define CHECK(cond, msg) \
38 do { \
39 if (!(cond)) { \
40 printf("ex_clipboard: FAIL: %s\n", msg); \
41 failures++; \
42 } \
43 } while (0)
44
45#if defined(__linux__)
46#include <X11/Xatom.h>
47#include <X11/Xlib.h>
48#include <sys/select.h>
49
50/* Fetch a target from a selection on a PRIVATE connection, which forces the request
51 * through n_clipboard's serving thread (this process owns the selection). Returns a
52 * malloc'd string or NULL. */
53static char* fetch_target(const char* sel_name, const char* target_name) {
54 Display* d = XOpenDisplay(NULL);
55 Window w;
56 Atom sel, target, prop;
57 char* out = NULL;
58 int fd, tries;
59 if (!d)
60 return NULL;
61 w = XCreateSimpleWindow(d, RootWindow(d, DefaultScreen(d)), 0, 0, 1, 1, 0, 0, 0);
62 sel = XInternAtom(d, sel_name, False);
63 target = XInternAtom(d, target_name, False);
64 prop = XInternAtom(d, "EX_CLIP_PROP", False);
65 XConvertSelection(d, sel, target, prop, w, CurrentTime);
66 XFlush(d);
67 fd = ConnectionNumber(d);
68 for (tries = 0; tries < 20 && !out; tries++) {
69 fd_set fds;
70 struct timeval tv;
71 FD_ZERO(&fds);
72 FD_SET(fd, &fds);
73 tv.tv_sec = 0;
74 tv.tv_usec = 100000;
75 select(fd + 1, &fds, NULL, NULL, &tv);
76 while (XPending(d)) {
77 XEvent ev;
78 XNextEvent(d, &ev);
79 if (ev.type == SelectionNotify) {
80 if (ev.xselection.property != None) {
81 Atom rt;
82 int rf;
83 unsigned long ni, ba;
84 unsigned char* data = NULL;
85 if (XGetWindowProperty(d, w, prop, 0, (~0L), False, AnyPropertyType, &rt, &rf, &ni, &ba, &data) == Success && data) {
86 out = malloc(ni + 1);
87 if (out) {
88 memcpy(out, data, ni);
89 out[ni] = '\0';
90 }
91 XFree(data);
92 }
93 }
94 tries = 20;
95 break;
96 }
97 }
98 }
99 XDestroyWindow(d, w);
100 XCloseDisplay(d);
101 return out;
102}
103#endif
104
105int main(void) {
107 if (n_clipboard_init() != 0) {
108 printf("ex_clipboard: SKIP (no X11 display)\n");
109 return 0;
110 }
111 CHECK(n_clipboard_available() == 1, "available after init");
112
113 /* own-selection round trip */
114 n_clipboard_set(N_CLIPBOARD_CLIPBOARD, "hello clipboard");
115 {
117 CHECK(c && strcmp(c, "hello clipboard") == 0, "clipboard round trip");
118 free(c);
119 }
120 n_clipboard_set(N_CLIPBOARD_PRIMARY, "hello primary");
121 {
123 CHECK(p && strcmp(p, "hello primary") == 0, "primary round trip");
124 free(p);
125 }
126
127#if defined(__linux__)
128 /* a separate X client fetches the text as the targets a strict consumer (Chromium)
129 asks for, proving the serving thread answers them */
130 {
131 char* c = fetch_target("CLIPBOARD", "text/plain;charset=utf-8");
132 CHECK(c && strcmp(c, "hello clipboard") == 0, "serve text/plain;charset=utf-8 (Chromium)");
133 free(c);
134 c = fetch_target("CLIPBOARD", "UTF8_STRING");
135 CHECK(c && strcmp(c, "hello clipboard") == 0, "serve UTF8_STRING");
136 free(c);
137 c = fetch_target("PRIMARY", "STRING");
138 CHECK(c && strcmp(c, "hello primary") == 0, "serve STRING on PRIMARY");
139 free(c);
140 /* TARGETS must be answered (Chromium queries it before pasting) */
141 c = fetch_target("CLIPBOARD", "TARGETS");
142 CHECK(c != NULL, "answer a TARGETS query");
143 free(c);
144 }
145#endif
146
148 if (failures == 0)
149 printf("ex_clipboard: all checks passed\n");
150 else
151 printf("ex_clipboard: %d checks FAILED\n", failures);
152 return failures ? 1 : 0;
153}
#define CHECK(cond, msg)
static int failures
int main(void)
#define LOG_ERR
error conditions
Definition n_log.h:76
void set_log_level(const int log_level)
Set the global log level value ( static int LOG_LEVEL )
Definition n_log.c:121
int n_clipboard_set(int which, const char *text)
Own which selection and serve text to any app that requests it.
int n_clipboard_available(void)
Whether a real clipboard backend (X11 or Win32) is active on this platform.
int n_clipboard_init(void)
Start the clipboard backend (idempotent; also started lazily on first use).
char * n_clipboard_get(int which)
Fetch the current text of which selection from its owner.
void n_clipboard_destroy(void)
Stop the backend thread and release the display connection.
System clipboard: full X11 selection support on Linux, Win32 clipboard on Windows/MinGW.
#define N_CLIPBOARD_PRIMARY
the X11 PRIMARY selection (mouse select-to-copy / middle-click paste); a no-op on Windows,...
Definition n_clipboard.h:59
#define N_CLIPBOARD_CLIPBOARD
the Ctrl+C / Ctrl+V clipboard selection
Definition n_clipboard.h:56
Generic log system.