gschem
|
00001 /* gEDA - GPL Electronic Design Automation 00002 * gschem - gEDA Schematic Capture 00003 * Copyright (C) 1998-2010 gEDA Contributors (see ChangeLog for details) 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License as published by 00007 * the Free Software Foundation; either version 2 of the License, or 00008 * (at your option) any later version. 00009 * 00010 * This program is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 * GNU General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU General Public License 00016 * along with this program; if not, write to the Free Software 00017 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00018 */ 00019 #include <config.h> 00020 00021 #include <stdio.h> 00022 #ifdef HAVE_STRING_H 00023 #include <string.h> 00024 #endif 00025 #ifdef HAVE_UNISTD_H 00026 #include <unistd.h> 00027 #endif 00028 00029 #include "gschem.h" 00030 00031 #ifdef HAVE_LIBDMALLOC 00032 #include <dmalloc.h> 00033 #endif 00034 00035 #define MIME_TYPE_SCHEMATIC "application/x-geda-schematic" 00036 #define CLIP_TYPE_SCHEMATIC 1 00037 00038 /* \brief Callback for handling system clipboard owner change. 00039 * \par Function Description 00040 * 00041 */ 00042 static void 00043 clip_handle_owner_change (GtkClipboard *cb, GdkEvent *event, 00044 gpointer user_data) 00045 { 00046 GSCHEM_TOPLEVEL *w_current = (GSCHEM_TOPLEVEL *) user_data; 00047 00048 i_update_menus (w_current); 00049 } 00050 00051 static void 00052 clip_get (GtkClipboard *cb, GtkSelectionData *selection_data, 00053 guint info, gpointer user_data_or_owner) 00054 { 00055 GSCHEM_TOPLEVEL *w_current = (GSCHEM_TOPLEVEL *) user_data_or_owner; 00056 TOPLEVEL *toplevel = w_current->toplevel; 00057 GdkAtom type = gdk_atom_intern (MIME_TYPE_SCHEMATIC, FALSE); 00058 gchar *buf; 00059 if (info != CLIP_TYPE_SCHEMATIC) return; 00060 /* Convert the objects in the clipboard buffer to gEDA schematic 00061 * format */ 00062 buf = o_save_buffer (toplevel, w_current->clipboard_buffer); 00063 /* Set the selection appropriately */ 00064 gtk_selection_data_set (selection_data, type, 00065 8, /* 8-bit data (UTF-8) */ 00066 (guchar *) buf, 00067 (gint) strlen(buf)); 00068 g_free (buf); 00069 } 00070 00071 static void 00072 clip_clear (GtkClipboard *cb, gpointer user_data_or_owner) 00073 { 00074 GSCHEM_TOPLEVEL *w_current = user_data_or_owner; 00075 TOPLEVEL *toplevel = w_current->toplevel; 00076 00077 /* Free the objects in the clipboard buffer */ 00078 s_delete_object_glist (toplevel, w_current->clipboard_buffer); 00079 w_current->clipboard_buffer = NULL; 00080 } 00081 00082 /* \brief Initialises system clipboard support 00083 * \par Function Description 00084 * Registers a signal handler to detect if the clipboard has changed 00085 * and update the menu item sensitivity if necessary. 00086 */ 00087 void 00088 x_clipboard_init (GSCHEM_TOPLEVEL *w_current) 00089 { 00090 GtkClipboard *cb = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); 00091 g_signal_connect (G_OBJECT (cb), 00092 "owner-change", 00093 G_CALLBACK (clip_handle_owner_change), 00094 w_current); 00095 } 00096 00097 /* \brief Initialises system clipboard support 00098 * \par Function Description 00099 * Registers a signal handler to detect if the clipboard has changed 00100 * and update the menu item sensitivity if necessary. 00101 */ 00102 void 00103 x_clipboard_finish (GSCHEM_TOPLEVEL *w_current) 00104 { 00105 GtkClipboard *cb = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); 00106 g_signal_handlers_disconnect_by_func (cb, clip_handle_owner_change, w_current); 00107 if (w_current->clipboard_buffer) 00108 gtk_clipboard_store (cb); 00109 } 00110 00111 struct query_usable { 00112 void (*callback) (int, void *); 00113 void *userdata; 00114 }; 00115 00116 00117 /* \brief Callback for determining if any clipboard targets are pastable 00118 * \par Function Description 00119 * 00120 * Checks if the clipboard targets match any format we recognise, then 00121 * calls back into a supplied callback function which is interested in 00122 * the TRUE / FALSE answer to whether we can paste from the clipboard. 00123 */ 00124 static void 00125 query_usable_targets_cb (GtkClipboard *clip, GdkAtom *targets, gint ntargets, 00126 gpointer data) 00127 { 00128 struct query_usable *cbinfo = data; 00129 int i; 00130 int is_usable = FALSE; 00131 00132 for (i = 0; i < ntargets; i++) { 00133 if (strcmp (gdk_atom_name (targets[i]), MIME_TYPE_SCHEMATIC) == 0) { 00134 is_usable = TRUE; 00135 break; 00136 } 00137 } 00138 00139 cbinfo->callback (is_usable, cbinfo->userdata); 00140 g_free (cbinfo); 00141 } 00142 00143 00144 /* \brief Checks if the system clipboard contains schematic data. 00145 * \par Function Description 00146 * Checks whether the current owner of the system clipboard is 00147 * advertising gEDA schematic data. 00148 * 00149 * The check is performed asynchronously. When a response is 00150 * recieved, the provided callback is called with a TRUE / FALSE 00151 * result. 00152 * 00153 * \param [in] w_current The current GSCHEM_TOPLEVEL. 00154 * \param [in] callback The callback to recieve the response. 00155 * \param [in] userdata Arbitrary data to pass the callback. 00156 */ 00157 void 00158 x_clipboard_query_usable (GSCHEM_TOPLEVEL *w_current, 00159 void (*callback) (int, void *), void *userdata) 00160 { 00161 GtkClipboard *clip = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); 00162 struct query_usable *cbinfo; 00163 00164 cbinfo = g_new (struct query_usable, 1); 00165 cbinfo->callback = callback; 00166 cbinfo->userdata = userdata; 00167 00168 gtk_clipboard_request_targets (clip, query_usable_targets_cb, cbinfo); 00169 } 00170 00171 /* \brief Set the contents of the system clipboard. 00172 * \par Function Description 00173 * Set the system clipboard to contain the gschem objects listed in \a 00174 * object_list. 00175 * 00176 * \param [in,out] w_current The current GSCHEM_TOPLEVEL. 00177 * \param [in] object_list The objects to put in the clipboard. 00178 * 00179 * \return TRUE if the clipboard is successfully set. 00180 */ 00181 gboolean 00182 x_clipboard_set (GSCHEM_TOPLEVEL *w_current, const GList *object_list) 00183 { 00184 GtkClipboard *cb = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); 00185 GtkTargetEntry target = { MIME_TYPE_SCHEMATIC, 0, 00186 CLIP_TYPE_SCHEMATIC }; 00187 TOPLEVEL *toplevel = w_current->toplevel; 00188 gboolean result; 00189 00190 /* Clear the clipboard buffer */ 00191 if (w_current->clipboard_buffer) 00192 gtk_clipboard_clear (cb); 00193 00194 /* Copy the objects to the clipboard buffer */ 00195 w_current->clipboard_buffer = 00196 o_glist_copy_all (toplevel, object_list, w_current->clipboard_buffer); 00197 00198 /* Advertise that the data is available */ 00199 result = gtk_clipboard_set_with_data (cb, &target, 1, 00200 clip_get, clip_clear, w_current); 00201 00202 /* Hint that the data can be stored to be accessed after the program 00203 * has quit. */ 00204 gtk_clipboard_set_can_store (cb, NULL, 0); 00205 00206 return result; 00207 } 00208 00209 /* \brief Get the contents of the system clipboard. 00210 * \par Function Description 00211 * If the system clipboard contains schematic data, retrieve it. 00212 * 00213 * \param [in,out] w_current The current GSCHEM_TOPLEVEL. 00214 * 00215 * \returns Any OBJECTs retrieved from the system clipboard, or NULL 00216 * if none were available. 00217 */ 00218 GList * 00219 x_clipboard_get (GSCHEM_TOPLEVEL *w_current) 00220 { 00221 GtkClipboard *cb = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD); 00222 TOPLEVEL *toplevel = w_current->toplevel; 00223 GdkAtom type = gdk_atom_intern (MIME_TYPE_SCHEMATIC, FALSE); 00224 GtkSelectionData *selection_data; 00225 GList *object_list = NULL; 00226 const guchar *buf; 00227 GError * err = NULL; 00228 00229 /* Try to get the contents of the clipboard */ 00230 selection_data = gtk_clipboard_wait_for_contents (cb, type); 00231 if (selection_data == NULL) return FALSE; 00232 00233 /* Convert the data buffer to OBJECTs */ 00234 #if GTK_CHECK_VERSION(2,14,0) 00235 buf = gtk_selection_data_get_data (selection_data); 00236 #else 00237 buf = selection_data->data; 00238 #endif 00239 00240 object_list = o_read_buffer (toplevel, object_list, 00241 (gchar *) buf, -1, "Clipboard", &err); 00242 00243 if (err) { 00244 GtkWidget * dialog = gtk_message_dialog_new_with_markup 00245 (GTK_WINDOW (w_current->main_window), 00246 GTK_DIALOG_DESTROY_WITH_PARENT, 00247 GTK_MESSAGE_ERROR, 00248 GTK_BUTTONS_OK, 00249 _("<b>Invalid schematic on clipboard.</b>\n\nAn error occurred while inserting clipboard data: %s."), 00250 err->message); 00251 gtk_window_set_title (GTK_WINDOW (dialog), _("Clipboard insertion failed")); 00252 00253 gtk_dialog_run (GTK_DIALOG (dialog)); 00254 gtk_widget_destroy (dialog); 00255 g_error_free(err); 00256 } 00257 gtk_selection_data_free (selection_data); 00258 return object_list; 00259 }