Remove extra debug message
[geda-gaf.git] / gschem / src / x_clipboard.c
blobebee5bfd5a44e91c8dec382e0c70f15f7c8e7e87
1 /* gEDA - GPL Electronic Design Automation
2 * gschem - gEDA Schematic Capture
3 * Copyright (C) 1998-2019 gEDA Contributors (see ChangeLog for details)
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 #include <config.h>
21 #include <stdio.h>
22 #ifdef HAVE_STRING_H
23 #include <string.h>
24 #endif
25 #ifdef HAVE_UNISTD_H
26 #include <unistd.h>
27 #endif
29 #include "gschem.h"
30 #include "actions.decl.x"
32 #define MIME_TYPE_SCHEMATIC "application/x-geda-schematic"
33 #define CLIP_TYPE_SCHEMATIC 1
35 /* \brief Callback for handling system clipboard owner change.
36 * \par Function Description
39 static void
40 clip_handle_owner_change (GtkClipboard *cb, GdkEvent *event,
41 gpointer user_data)
43 GschemToplevel *w_current = (GschemToplevel *) user_data;
45 x_clipboard_update_menus (w_current);
48 static void
49 clip_get (GtkClipboard *cb, GtkSelectionData *selection_data,
50 guint info, gpointer user_data_or_owner)
52 GschemToplevel *w_current = (GschemToplevel *) user_data_or_owner;
53 GdkAtom type = gdk_atom_intern (MIME_TYPE_SCHEMATIC, FALSE);
54 gchar *buf;
55 if (info != CLIP_TYPE_SCHEMATIC) return;
56 /* Convert the objects in the clipboard buffer to gEDA schematic
57 * format */
58 buf = o_save_buffer (w_current->clipboard_buffer);
59 /* Set the selection appropriately */
60 gtk_selection_data_set (selection_data, type,
61 8, /* 8-bit data (UTF-8) */
62 (guchar *) buf,
63 (gint) strlen(buf));
64 g_free (buf);
67 static void
68 clip_clear (GtkClipboard *cb, gpointer user_data_or_owner)
70 GschemToplevel *w_current = user_data_or_owner;
71 TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current);
73 /* Free the objects in the clipboard buffer */
74 s_delete_object_glist (toplevel, w_current->clipboard_buffer);
75 w_current->clipboard_buffer = NULL;
78 /* \brief Initialises system clipboard support
79 * \par Function Description
80 * Registers a signal handler to detect if the clipboard has changed
81 * and update the menu item sensitivity if necessary.
83 void
84 x_clipboard_init (GschemToplevel *w_current)
86 GtkClipboard *cb = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
87 g_signal_connect (G_OBJECT (cb),
88 "owner-change",
89 G_CALLBACK (clip_handle_owner_change),
90 w_current);
93 /* \brief Initialises system clipboard support
94 * \par Function Description
95 * Registers a signal handler to detect if the clipboard has changed
96 * and update the menu item sensitivity if necessary.
98 void
99 x_clipboard_finish (GschemToplevel *w_current)
101 GtkClipboard *cb = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
102 g_signal_handlers_disconnect_by_func (cb, clip_handle_owner_change, w_current);
103 if (w_current->clipboard_buffer)
104 gtk_clipboard_store (cb);
107 struct query_usable {
108 void (*callback) (int, void *);
109 void *userdata;
113 /* \brief Callback for determining if any clipboard targets are pastable
114 * \par Function Description
116 * Checks if the clipboard targets match any format we recognise, then
117 * calls back into a supplied callback function which is interested in
118 * the TRUE / FALSE answer to whether we can paste from the clipboard.
120 static void
121 query_usable_targets_cb (GtkClipboard *clip, GdkAtom *targets, gint ntargets,
122 gpointer data)
124 struct query_usable *cbinfo = data;
125 int i;
126 int is_usable = FALSE;
128 for (i = 0; i < ntargets; i++) {
129 if (strcmp (gdk_atom_name (targets[i]), MIME_TYPE_SCHEMATIC) == 0) {
130 is_usable = TRUE;
131 break;
135 cbinfo->callback (is_usable, cbinfo->userdata);
136 g_free (cbinfo);
140 /* \brief Checks if the system clipboard contains schematic data.
141 * \par Function Description
142 * Checks whether the current owner of the system clipboard is
143 * advertising gEDA schematic data.
145 * The check is performed asynchronously. When a response is
146 * recieved, the provided callback is called with a TRUE / FALSE
147 * result.
149 * \param [in] w_current The current GschemToplevel.
150 * \param [in] callback The callback to recieve the response.
151 * \param [in] userdata Arbitrary data to pass the callback.
153 static void
154 query_usable (GschemToplevel *w_current,
155 void (*callback) (int, void *), void *userdata)
157 GtkClipboard *clip = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
158 struct query_usable *cbinfo;
160 cbinfo = g_new (struct query_usable, 1);
161 cbinfo->callback = callback;
162 cbinfo->userdata = userdata;
164 gtk_clipboard_request_targets (clip, query_usable_targets_cb, cbinfo);
167 /*! \brief Asynchronous callback to update the sensitivity of the
168 * Edit/Paste menu item.
170 static void
171 clipboard_usable_cb (int usable, void *userdata)
173 GschemToplevel *w_current = GSCHEM_TOPLEVEL (userdata);
175 gschem_action_set_sensitive (action_clipboard_paste, usable, w_current);
178 /*! \brief Update the sensitivity of the Edit/Paste menu item.
180 void
181 x_clipboard_update_menus(GschemToplevel *w_current)
183 query_usable (w_current, clipboard_usable_cb, w_current);
186 /* \brief Set the contents of the system clipboard.
187 * \par Function Description
188 * Set the system clipboard to contain the gschem objects listed in \a
189 * object_list.
191 * \param [in,out] w_current The current GschemToplevel.
192 * \param [in] object_list The objects to put in the clipboard.
194 * \return TRUE if the clipboard is successfully set.
196 gboolean
197 x_clipboard_set (GschemToplevel *w_current, const GList *object_list)
199 GtkClipboard *cb = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
200 GtkTargetEntry target = { MIME_TYPE_SCHEMATIC, 0,
201 CLIP_TYPE_SCHEMATIC };
202 TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current);
203 gboolean result;
205 /* Clear the clipboard buffer */
206 if (w_current->clipboard_buffer)
207 gtk_clipboard_clear (cb);
209 /* Copy the objects to the clipboard buffer */
210 w_current->clipboard_buffer =
211 o_glist_copy_all (toplevel, object_list, w_current->clipboard_buffer);
213 /* Advertise that the data is available */
214 result = gtk_clipboard_set_with_data (cb, &target, 1,
215 clip_get, clip_clear, w_current);
217 /* Hint that the data can be stored to be accessed after the program
218 * has quit. */
219 gtk_clipboard_set_can_store (cb, NULL, 0);
221 return result;
224 /* \brief Get the contents of the system clipboard.
225 * \par Function Description
226 * If the system clipboard contains schematic data, retrieve it.
228 * \param [in,out] w_current The current GschemToplevel.
230 * \returns Any OBJECTs retrieved from the system clipboard, or NULL
231 * if none were available.
233 GList *
234 x_clipboard_get (GschemToplevel *w_current)
236 GtkClipboard *cb = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
237 TOPLEVEL *toplevel = gschem_toplevel_get_toplevel (w_current);
238 GdkAtom type = gdk_atom_intern (MIME_TYPE_SCHEMATIC, FALSE);
239 GtkSelectionData *selection_data;
240 GList *object_list = NULL;
241 const guchar *buf;
242 GError * err = NULL;
244 /* Try to get the contents of the clipboard */
245 selection_data = gtk_clipboard_wait_for_contents (cb, type);
246 if (selection_data == NULL) return FALSE;
248 /* Convert the data buffer to OBJECTs */
249 #if GTK_CHECK_VERSION(2,14,0)
250 buf = gtk_selection_data_get_data (selection_data);
251 #else
252 buf = selection_data->data;
253 #endif
255 object_list = o_read_buffer (toplevel, object_list,
256 (gchar *) buf, -1, "Clipboard", &err);
258 if (err) {
259 GtkWidget * dialog = gtk_message_dialog_new_with_markup
260 (GTK_WINDOW (w_current->main_window),
261 GTK_DIALOG_DESTROY_WITH_PARENT,
262 GTK_MESSAGE_ERROR,
263 GTK_BUTTONS_OK,
264 _("<b>Invalid schematic on clipboard.</b>\n\nAn error occurred while inserting clipboard data: %s."),
265 err->message);
266 gtk_window_set_title (GTK_WINDOW (dialog), _("Clipboard insertion failed"));
268 gtk_dialog_run (GTK_DIALOG (dialog));
269 gtk_widget_destroy (dialog);
270 g_error_free(err);
272 gtk_selection_data_free (selection_data);
273 return object_list;