gschem

x_clipboard.c

Go to the documentation of this file.
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 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines