1 | #include <gtk/gtk.h> |
2 | |
3 | #ifdef GDK_WINDOWING_WAYLAND |
4 | #include "wayland/gdkwayland.h" |
5 | #endif |
6 | |
7 | #ifdef G_OS_WIN32 |
8 | #include <io.h> |
9 | #include <process.h> |
10 | #endif |
11 | |
12 | G_GNUC_NORETURN static void |
13 | got_string_cb (GObject *source, |
14 | GAsyncResult *result, |
15 | gpointer data) |
16 | { |
17 | GdkClipboard *clipboard = GDK_CLIPBOARD (source); |
18 | GError *error = NULL; |
19 | char *text; |
20 | |
21 | text = gdk_clipboard_read_text_finish (clipboard, result, error: &error); |
22 | if (text) |
23 | { |
24 | g_print (format: "%s" , text); |
25 | g_free (mem: text); |
26 | } |
27 | else |
28 | { |
29 | g_print (format: "ERROR: %s" , error->message); |
30 | g_clear_error (err: &error); |
31 | } |
32 | |
33 | exit (status: 0); |
34 | } |
35 | |
36 | G_GNUC_NORETURN static void |
37 | got_text_cb (GObject *source, |
38 | GAsyncResult *result, |
39 | gpointer data) |
40 | { |
41 | GdkClipboard *clipboard = GDK_CLIPBOARD (source); |
42 | GError *error = NULL; |
43 | char *text; |
44 | |
45 | text = gdk_clipboard_read_text_finish (clipboard, result, error: &error); |
46 | if (text) |
47 | { |
48 | int fd; |
49 | char *name; |
50 | |
51 | fd = g_file_open_tmp (tmpl: "XXXXXX.out" , name_used: &name, error: &error); |
52 | if (error) |
53 | g_error ("Failed to create tmp file: %s" , error->message); |
54 | close (fd: fd); |
55 | g_file_set_contents (filename: name, contents: text, length: -1, error: &error); |
56 | g_print (format: "%s" , name); |
57 | g_free (mem: text); |
58 | g_free (mem: name); |
59 | } |
60 | else |
61 | { |
62 | g_print (format: "ERROR: %s" , error->message); |
63 | g_clear_error (err: &error); |
64 | } |
65 | |
66 | exit (status: 0); |
67 | } |
68 | |
69 | G_GNUC_NORETURN static void |
70 | got_texture_cb (GObject *source, |
71 | GAsyncResult *result, |
72 | gpointer data) |
73 | { |
74 | GdkClipboard *clipboard = GDK_CLIPBOARD (source); |
75 | GError *error = NULL; |
76 | GdkTexture *texture; |
77 | |
78 | texture = gdk_clipboard_read_texture_finish (clipboard, result, error: &error); |
79 | if (texture) |
80 | { |
81 | int fd; |
82 | char *name; |
83 | |
84 | fd = g_file_open_tmp (tmpl: "XXXXXX.out" , name_used: &name, error: &error); |
85 | if (error) |
86 | g_error ("Failed to create tmp file: %s" , error->message); |
87 | close (fd: fd); |
88 | gdk_texture_save_to_png (texture, filename: name); |
89 | g_print (format: "%s" , name); |
90 | g_object_unref (object: texture); |
91 | g_free (mem: name); |
92 | } |
93 | else |
94 | { |
95 | g_print (format: "ERROR: %s" , error->message); |
96 | g_clear_error (err: &error); |
97 | } |
98 | |
99 | exit (status: 0); |
100 | } |
101 | |
102 | G_GNUC_NORETURN static void |
103 | got_file (GObject *source, |
104 | GAsyncResult *result, |
105 | gpointer data) |
106 | { |
107 | GdkClipboard *clipboard = GDK_CLIPBOARD (source); |
108 | GError *error = NULL; |
109 | const GValue *value; |
110 | |
111 | value = gdk_clipboard_read_value_finish (clipboard, result, error: &error); |
112 | if (value) |
113 | { |
114 | GFile *file = g_value_get_object (value); |
115 | char *path = g_file_get_path (file); |
116 | g_print (format: "%s" , path); |
117 | g_free (mem: path); |
118 | } |
119 | else |
120 | { |
121 | g_print (format: "ERROR: %s" , error->message); |
122 | g_clear_error (err: &error); |
123 | } |
124 | |
125 | exit (status: 0); |
126 | } |
127 | |
128 | G_GNUC_NORETURN static void |
129 | got_files (GObject *source, |
130 | GAsyncResult *result, |
131 | gpointer data) |
132 | { |
133 | GdkClipboard *clipboard = GDK_CLIPBOARD (source); |
134 | GError *error = NULL; |
135 | const GValue *value; |
136 | |
137 | value = gdk_clipboard_read_value_finish (clipboard, result, error: &error); |
138 | if (value) |
139 | { |
140 | GSList *files = g_value_get_boxed (value); |
141 | for (GSList *l = files; l; l = l->next) |
142 | { |
143 | GFile *file = l->data; |
144 | char *path = g_file_get_path (file); |
145 | if (l != files) |
146 | g_print (format: ":" ); |
147 | g_print (format: "%s" , path); |
148 | g_free (mem: path); |
149 | } |
150 | } |
151 | else |
152 | { |
153 | g_print (format: "ERROR: %s" , error->message); |
154 | g_clear_error (err: &error); |
155 | } |
156 | |
157 | exit (status: 0); |
158 | } |
159 | |
160 | G_GNUC_NORETURN static void |
161 | got_color (GObject *source, |
162 | GAsyncResult *result, |
163 | gpointer data) |
164 | { |
165 | GdkClipboard *clipboard = GDK_CLIPBOARD (source); |
166 | GError *error = NULL; |
167 | const GValue *value; |
168 | |
169 | value = gdk_clipboard_read_value_finish (clipboard, result, error: &error); |
170 | if (value) |
171 | { |
172 | GdkRGBA *color = g_value_get_boxed (value); |
173 | char *s = gdk_rgba_to_string (rgba: color); |
174 | g_print (format: "%s" , s); |
175 | g_free (mem: s); |
176 | } |
177 | else |
178 | { |
179 | g_print (format: "ERROR: %s" , error->message); |
180 | g_clear_error (err: &error); |
181 | } |
182 | |
183 | exit (status: 0); |
184 | } |
185 | |
186 | static const char *action; |
187 | static const char *type; |
188 | static const char *value; |
189 | static gulong handler; |
190 | |
191 | static void |
192 | do_it (GObject *object, |
193 | GParamSpec *pspec) |
194 | { |
195 | GdkClipboard *clipboard; |
196 | |
197 | if (object) |
198 | g_signal_handler_disconnect (instance: object, handler_id: handler); |
199 | |
200 | clipboard = gdk_display_get_clipboard (display: gdk_display_get_default ()); |
201 | |
202 | if (strcmp (s1: action, s2: "info" ) == 0) |
203 | { |
204 | GdkContentFormats *formats; |
205 | char *s; |
206 | |
207 | formats = gdk_clipboard_get_formats (clipboard); |
208 | s = gdk_content_formats_to_string (formats); |
209 | g_print (format: "%s\n" , s); |
210 | g_free (mem: s); |
211 | } |
212 | else if (strcmp (s1: action, s2: "set" ) == 0) |
213 | { |
214 | GdkContentFormats *formats; |
215 | char *s; |
216 | |
217 | if (strcmp (s1: type, s2: "string" ) == 0) |
218 | { |
219 | gdk_clipboard_set_text (clipboard, text: value); |
220 | } |
221 | else if (strcmp (s1: type, s2: "text" ) == 0) |
222 | { |
223 | char *contents; |
224 | gsize len; |
225 | |
226 | if (!g_file_get_contents (filename: value, contents: &contents, length: &len, NULL)) |
227 | g_error ("Failed to read %s\n" , value); |
228 | |
229 | gdk_clipboard_set_text (clipboard, text: contents); |
230 | g_free (mem: contents); |
231 | } |
232 | else if (strcmp (s1: type, s2: "image" ) == 0) |
233 | { |
234 | GFile *file; |
235 | GdkTexture *texture; |
236 | |
237 | file = g_file_new_for_commandline_arg (arg: value); |
238 | texture = gdk_texture_new_from_file (file, NULL); |
239 | if (!texture) |
240 | g_error ("Failed to read %s\n" , value); |
241 | |
242 | gdk_clipboard_set_texture (clipboard, texture); |
243 | g_object_unref (object: texture); |
244 | g_object_unref (object: file); |
245 | } |
246 | else if (strcmp (s1: type, s2: "file" ) == 0) |
247 | { |
248 | GFile *file; |
249 | |
250 | file = g_file_new_for_commandline_arg (arg: value); |
251 | gdk_clipboard_set (clipboard, G_TYPE_FILE, file); |
252 | g_object_unref (object: file); |
253 | } |
254 | else if (strcmp (s1: type, s2: "files" ) == 0) |
255 | { |
256 | char **strv; |
257 | GSList *files; |
258 | |
259 | strv = g_strsplit (string: value, delimiter: ":" , max_tokens: 0); |
260 | |
261 | files = NULL; |
262 | for (int i = 0; strv[i]; i++) |
263 | files = g_slist_append (list: files, data: g_file_new_for_commandline_arg (arg: strv[i])); |
264 | |
265 | gdk_clipboard_set (clipboard, GDK_TYPE_FILE_LIST, files); |
266 | |
267 | g_slist_free_full (list: files, free_func: g_object_unref); |
268 | g_strfreev (str_array: strv); |
269 | } |
270 | else if (strcmp (s1: type, s2: "color" ) == 0) |
271 | { |
272 | GdkRGBA color; |
273 | |
274 | gdk_rgba_parse (rgba: &color, spec: value); |
275 | gdk_clipboard_set (clipboard, GDK_TYPE_RGBA, &color); |
276 | } |
277 | else |
278 | g_error ("can't set %s" , type); |
279 | |
280 | formats = gdk_clipboard_get_formats (clipboard); |
281 | s = gdk_content_formats_to_string (formats); |
282 | g_print (format: "%s\n" , s); |
283 | g_free (mem: s); |
284 | } |
285 | else if (strcmp (s1: action, s2: "get" ) == 0) |
286 | { |
287 | if (strcmp (s1: type, s2: "string" ) == 0) |
288 | { |
289 | gdk_clipboard_read_text_async (clipboard, NULL, callback: got_string_cb, NULL); |
290 | } |
291 | else if (strcmp (s1: type, s2: "text" ) == 0) |
292 | { |
293 | gdk_clipboard_read_text_async (clipboard, NULL, callback: got_text_cb, NULL); |
294 | } |
295 | else if (strcmp (s1: type, s2: "image" ) == 0) |
296 | { |
297 | gdk_clipboard_read_texture_async (clipboard, NULL, callback: got_texture_cb, NULL); |
298 | } |
299 | else if (strcmp (s1: type, s2: "file" ) == 0) |
300 | { |
301 | gdk_clipboard_read_value_async (clipboard, G_TYPE_FILE, io_priority: 0, NULL, callback: got_file, NULL); |
302 | } |
303 | else if (strcmp (s1: type, s2: "files" ) == 0) |
304 | { |
305 | gdk_clipboard_read_value_async (clipboard, GDK_TYPE_FILE_LIST, io_priority: 0, NULL, callback: got_files, NULL); |
306 | } |
307 | else if (strcmp (s1: type, s2: "color" ) == 0) |
308 | { |
309 | gdk_clipboard_read_value_async (clipboard, GDK_TYPE_RGBA, io_priority: 0, NULL, callback: got_color, NULL); |
310 | } |
311 | else |
312 | g_error ("can't get %s" , type); |
313 | } |
314 | else |
315 | g_error ("can only set, get or info" ); |
316 | } |
317 | |
318 | int |
319 | main (int argc, char *argv[]) |
320 | { |
321 | gboolean done = FALSE; |
322 | |
323 | if (argc < 2) |
324 | g_error ("too few arguments" ); |
325 | |
326 | action = argv[1]; |
327 | |
328 | if (strcmp (s1: action, s2: "info" ) == 0) |
329 | { |
330 | } |
331 | else if (strcmp (s1: action, s2: "set" ) == 0) |
332 | { |
333 | if (argc < 4) |
334 | g_error ("too few arguments for set" ); |
335 | |
336 | type = argv[2]; |
337 | value = argv[3]; |
338 | } |
339 | else if (strcmp (s1: action, s2: "get" ) == 0) |
340 | { |
341 | if (argc < 3) |
342 | g_error ("too few arguments for get" ); |
343 | |
344 | type = argv[2]; |
345 | } |
346 | else |
347 | g_error ("can only set or get" ); |
348 | |
349 | gtk_init (); |
350 | |
351 | /* Don't wait for a window manager to give us focus when |
352 | * we may be running on bare wm-less X. |
353 | */ |
354 | #ifdef GDK_WINDOWING_WAYLAND |
355 | if (GDK_IS_WAYLAND_DISPLAY (gdk_display_get_default ())) |
356 | { |
357 | GtkWidget *window; |
358 | |
359 | window = gtk_window_new (); |
360 | gtk_window_present (GTK_WINDOW (window)); |
361 | handler = g_signal_connect (window, "notify::is-active" , G_CALLBACK (do_it), NULL); |
362 | } |
363 | else |
364 | #endif |
365 | do_it (NULL, NULL); |
366 | |
367 | while (!done) |
368 | g_main_context_iteration (NULL, TRUE); |
369 | |
370 | return 0; |
371 | } |
372 | |