X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fui%2Fclipboard.cpp;h=bd3edadda28ab8487585e0c042015b0794d44a87;hb=886a6b71ce208597cc57040aa677f8693e4885bf;hp=227d57a964f240a2b141ce9e7dab20d4e4fbec70;hpb=dda97aeba7480d08320ebceecae13b8531db1b81;p=inkscape.git diff --git a/src/ui/clipboard.cpp b/src/ui/clipboard.cpp index 227d57a96..bd3edadda 100644 --- a/src/ui/clipboard.cpp +++ b/src/ui/clipboard.cpp @@ -44,6 +44,9 @@ #include "extension/output.h" #include "selection-chemistry.h" #include "libnr/nr-rect.h" +#include "libnr/nr-convert2geom.h" +#include <2geom/rect.h> +#include <2geom/transforms.h> #include "box3d.h" #include "gradient-drag.h" #include "sp-item.h" @@ -66,18 +69,33 @@ #include "svg/svg.h" // for sp_svg_transform_write, used in _copySelection #include "svg/css-ostringstream.h" // used in _parseColor #include "file.h" // for file_import, used in _pasteImage -#include "prefs-utils.h" // for prefs_get_string_attribute, used in _pasteImage +#include "preferences.h" // for used in _pasteImage #include "text-context.h" #include "text-editing.h" #include "tools-switch.h" -#include "libnr/n-art-bpath-2geom.h" #include "path-chemistry.h" +#include "id-clash.h" +#include "unit-constants.h" +#include "helper/png-write.h" +#include "svg/svg-color.h" +#include "sp-namedview.h" +#include "snap.h" /// @brief Made up mimetype to represent Gdk::Pixbuf clipboard contents #define CLIPBOARD_GDK_PIXBUF_TARGET "image/x-gdk-pixbuf" #define CLIPBOARD_TEXT_TARGET "text/plain" +#ifdef WIN32 +#include +// Clipboard Formats: http://msdn.microsoft.com/en-us/library/ms649013(VS.85).aspx +// On Windows, most graphical applications can handle CF_DIB/CF_BITMAP and/or CF_ENHMETAFILE +// GTK automatically presents an "image/bmp" target as CF_DIB/CF_BITMAP +// Presenting "image/x-emf" as CF_ENHMETAFILE must be done by Inkscape ? +#define CLIPBOARD_WIN32_EMF_TARGET "CF_ENHMETAFILE" +#define CLIPBOARD_WIN32_EMF_MIME "image/x-emf" +#endif + namespace Inkscape { namespace UI { @@ -95,6 +113,7 @@ public: virtual bool pastePathEffect(); virtual Glib::ustring getPathParameter(); virtual Glib::ustring getShapeOrTextObjectId(); + virtual const gchar *getFirstObjectID(); ClipboardManagerImpl(); ~ClipboardManagerImpl(); @@ -123,7 +142,7 @@ private: void _createInternalClipboard(); void _discardInternalClipboard(); Inkscape::XML::Node *_createClipNode(); - NR::scale _getScale(Geom::Point &, Geom::Point &, NR::Rect &, bool, bool); + Geom::Scale _getScale(Geom::Point const &, Geom::Point const &, Geom::Rect const &, bool, bool); Glib::ustring _getBestTarget(); void _setClipboardTargets(); void _setClipboardColor(guint32); @@ -154,7 +173,7 @@ ClipboardManagerImpl::ClipboardManagerImpl() _preferred_targets.push_back("image/svg+xml"); _preferred_targets.push_back("image/svg+xml-compressed"); #ifdef WIN32 - _preferred_targets.push_back("image/x-emf"); + _preferred_targets.push_back(CLIPBOARD_WIN32_EMF_MIME); #endif _preferred_targets.push_back("application/pdf"); _preferred_targets.push_back("image/x-adobe-illustrator"); @@ -251,7 +270,7 @@ bool ClipboardManagerImpl::paste(bool in_place) Glib::ustring target = _getBestTarget(); - // Special cases of clipboard content handling go here 00ff00 + // Special cases of clipboard content handling go here // Note that target priority is determined in _getBestTarget. // TODO: Handle x-special/gnome-copied-files and text/uri-list to support pasting files @@ -273,6 +292,40 @@ bool ClipboardManagerImpl::paste(bool in_place) return true; } +/** + * @brief Returns the id of the first visible copied object + */ +const gchar *ClipboardManagerImpl::getFirstObjectID() +{ + SPDocument *tempdoc = _retrieveClipboard("image/x-inkscape-svg"); + if ( tempdoc == NULL ) { + return NULL; + } + + Inkscape::XML::Node + *root = sp_document_repr_root(tempdoc); + + if (!root) + return NULL; + + Inkscape::XML::Node *ch = sp_repr_children(root); + while (ch != NULL && + strcmp(ch->name(), "svg:g") && + strcmp(ch->name(), "svg:path") && + strcmp(ch->name(), "svg:use") && + strcmp(ch->name(), "svg:text") && + strcmp(ch->name(), "svg:image") && + strcmp(ch->name(), "svg:rect") + ) + ch = ch->next(); + + if (ch) { + return ch->attribute("id"); + } + + return NULL; +} + /** * @brief Implements the Paste Style action @@ -354,15 +407,15 @@ bool ClipboardManagerImpl::pasteSize(bool separately, bool apply_x, bool apply_y if (separately) { for (GSList *i = const_cast(selection->itemList()) ; i ; i = i->next) { SPItem *item = SP_ITEM(i->data); - NR::Maybe obj_size = sp_item_bbox_desktop(item); - if ( !obj_size || obj_size->isEmpty() ) continue; + Geom::OptRect obj_size = sp_item_bbox_desktop(item); + if ( !obj_size ) continue; sp_item_scale_rel(item, _getScale(min, max, *obj_size, apply_x, apply_y)); } } // resize the selection as a whole else { - NR::Maybe sel_size = selection->bounds(); - if ( sel_size && !sel_size->isEmpty() ) { + Geom::OptRect sel_size = selection->bounds(); + if ( sel_size ) { sp_selection_scale_relative(selection, sel_size->midpoint(), _getScale(min, max, *sel_size, apply_x, apply_y)); } @@ -401,7 +454,7 @@ bool ClipboardManagerImpl::pastePathEffect() if ( effect ) { _pasteDefs(tempdoc); // make sure all selected items are converted to paths first (i.e. rectangles) - sp_selected_path_to_curves(false); + sp_selected_path_to_curves(desktop, false); for (GSList *item = const_cast(selection->itemList()) ; item ; item = item->next) { _applyPathEffect(reinterpret_cast(item->data), effect); } @@ -518,10 +571,10 @@ void ClipboardManagerImpl::_copySelection(Inkscape::Selection *selection) } } - NR::Maybe size = selection->bounds(); + Geom::OptRect size = selection->bounds(); if (size) { - sp_repr_set_point(_clipnode, "min", size->min().to_2geom()); - sp_repr_set_point(_clipnode, "max", size->max().to_2geom()); + sp_repr_set_point(_clipnode, "min", size->min()); + sp_repr_set_point(_clipnode, "max", size->max()); } g_slist_free(sorted_items); @@ -560,14 +613,15 @@ void ClipboardManagerImpl::_copyUsedDefs(SPItem *item) } } } - // For lpe items, copy liveeffect if applicable - // TODO: copy the whole effect stack. now it only copies current selected effect + // For lpe items, copy lpe stack if applicable if (SP_IS_LPE_ITEM(item)) { SPLPEItem *lpeitem = SP_LPE_ITEM (item); if (sp_lpe_item_has_path_effect(lpeitem)) { - Inkscape::LivePathEffect::LPEObjectReference* lperef = sp_lpe_item_get_current_lpereference(lpeitem); - if (lperef && lperef->lpeobject) { - _copyNode(SP_OBJECT_REPR(SP_OBJECT(lperef->lpeobject)), _doc, _defs); + for (PathEffectList::iterator it = lpeitem->path_effect_list->begin(); it != lpeitem->path_effect_list->end(); ++it) + { + LivePathEffectObject *lpeobj = (*it)->lpeobject; + if (lpeobj) + _copyNode(SP_OBJECT_REPR(SP_OBJECT(lpeobj)), _doc, _defs); } } } @@ -701,36 +755,60 @@ void ClipboardManagerImpl::_pasteDocument(SPDocument *clipdoc, bool in_place) Inkscape::XML::Node *obj_copy = _copyNode(obj, target_xmldoc, target_parent); pasted_objects = g_slist_prepend(pasted_objects, (gpointer) obj_copy); } - + + /* The pasted objects are at the origin of the document coordinates (i.e. the upper left corner + * of the bounding box of the pasted selection is aligned to the upper left page corner). + * Now we will move the pasted objects to where we want them to be, which is either at the + * original position ("in place") or at the location of the mouse pointer (optionaly with snapping + * to the grid) + */ + + Geom::Point rel_pos_original, rel_pos_mouse; + + // Calculate the relative location of the original objects + Inkscape::XML::Node *clipnode = sp_repr_lookup_name(root, "inkscape:clipboard", 1); + if (clipnode) { + Geom::Point min, max; + // Get two bounding box corners of the data in the clipboard (still in it's original position) + sp_repr_get_point(clipnode, "min", &min); //In desktop coordinates + sp_repr_get_point(clipnode, "max", &max); + // Calculate the upper-left page corner in desktop coordinates (where the pasted objects are located) + Geom::Point ul_page_corner = desktop->doc2dt(Geom::Point(0,0)); + // Calculate the upper-left bbox corner of the original objects + Geom::Point ul_sel_corner = Geom::Point(min[Geom::X], max[Geom::Y]); + // Now calculate how far we would have to move the pasted objects to get them + // at the location of the original + rel_pos_original = ul_sel_corner - ul_page_corner; // in desktop coordinates + } + + // Calculate the relative location of the mouse pointer Inkscape::Selection *selection = sp_desktop_selection(desktop); - selection->setReprList(pasted_objects); - - // move the selection to the right position - if(in_place) - { - Inkscape::XML::Node *clipnode = sp_repr_lookup_name(root, "inkscape:clipboard", 1); - if (clipnode) { - Geom::Point min, max; - sp_repr_get_point(clipnode, "min", &min); - sp_repr_get_point(clipnode, "max", &max); - - // this formula was discovered empyrically - min[Geom::Y] += ((max[Geom::Y] - min[Geom::Y]) - sp_document_height(target_document)); - sp_selection_move_relative(selection, NR::Point(min)); - } + selection->setReprList(pasted_objects); // Change the selection to the freshly pasted objects + sp_document_ensure_up_to_date(target_document); // Update (among other things) all curves in paths, for bounds() to work + + Geom::OptRect sel_bbox = selection->bounds(); //In desktop coordinates + // PS: We could also have used the min/max corners calculated above, instead of selection->bounds() because + // we know that after pasting the upper left corner of the selection will be aligend to the corresponding + // page corner. Using the boundingbox of the selection is more foolproof though + if (sel_bbox) { + Geom::Point pos_mouse = desktop->point(); //Location of mouse pointer in desktop coordinates + // Now calculate how far we would have to move the pasted objects to get their + // midpoint at the location of the mouse pointer + rel_pos_mouse = pos_mouse - to_2geom(sel_bbox->midpoint()); } - // copied from former sp_selection_paste in selection-chemistry.cpp - else { - sp_document_ensure_up_to_date(target_document); - NR::Maybe sel_size = selection->bounds(); - - NR::Point m( desktop->point() ); - if (sel_size) { - m -= sel_size->midpoint(); - } - sp_selection_move_relative(selection, m); + + // Determine which offset we need to apply to the pasted objects + Geom::Point offset; + if (in_place) { // Align the pasted objects with their originals + offset = rel_pos_original; + } else { // Stick to the grid if snapping is enabled, otherwise paste at mouse position; + SnapManager &m = desktop->namedview->snap_manager; + m.setup(desktop, false); //Don't display the snapindicator + offset = rel_pos_original + m.multipleOfGridPitch(rel_pos_mouse - rel_pos_original); } - + + // Apply the offset to the pasted objects + sp_selection_move_relative(selection, offset); g_slist_free(pasted_objects); } @@ -751,29 +829,9 @@ void ClipboardManagerImpl::_pasteDefs(SPDocument *clipdoc) *target_defs = SP_OBJECT_REPR(SP_DOCUMENT_DEFS(target_document)); Inkscape::XML::Document *target_xmldoc = sp_document_repr_doc(target_document); + prevent_id_clashes(clipdoc, target_document); + for (Inkscape::XML::Node *def = defs->firstChild() ; def ; def = def->next()) { - /// @todo TODO: implement def id collision resolution in ClipboardManagerImpl::_pasteDefs() - - /* - // simplistic solution: when a collision occurs, add "a" to id until it's unique - Glib::ustring pasted_id = def->attribute("id"); - if ( pasted_id.empty() ) continue; // defs without id are useless - Glib::ustring pasted_id_original = pasted_id; - - while(sp_repr_lookup_child(target_defs, "id", pasted_id.data())) { - pasted_id.append("a"); - } - - if ( pasted_id != pasted_id_original ) { - def->setAttribute("id", pasted_id.data()); - // Update the id in the rest of the document so there are no dangling references - // How to do that? - _changeIdReferences(clipdoc, pasted_id_original, pasted_id); - } - */ - if (sp_repr_lookup_child(target_defs, "id", def->attribute("id"))) - continue; // skip duplicate defs - temporary non-solution - _copyNode(def, target_xmldoc, target_defs); } } @@ -800,13 +858,14 @@ bool ClipboardManagerImpl::_pasteImage() // in 1 second. time_t rawtime; char image_filename[128]; - gchar const *save_folder; time(&rawtime); strftime(image_filename, 128, "inkscape_pasted_image_%Y%m%d_%H%M%S.png", localtime( &rawtime )); - save_folder = (gchar const *) prefs_get_string_attribute("dialogs.save_as", "path"); + /// @todo Check whether the encoding is correct here + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + std::string save_folder = Glib::filename_from_utf8(prefs->getString("/dialogs/save_as/path")); - gchar *image_path = g_build_filename(save_folder, image_filename, NULL); + gchar *image_path = g_build_filename(save_folder.data(), image_filename, NULL); img->save(image_path, "png"); file_import(doc, image_path, NULL); g_free(image_path); @@ -844,6 +903,7 @@ bool ClipboardManagerImpl::_pasteText() */ SPCSSAttr *ClipboardManagerImpl::_parseColor(const Glib::ustring &text) { +// TODO reuse existing code instead of replicating here. Glib::ustring::size_type len = text.bytes(); char *str = const_cast(text.data()); bool attempt_alpha = false; @@ -926,16 +986,47 @@ SPDocument *ClipboardManagerImpl::_retrieveClipboard(Glib::ustring required_targ return NULL; } - if ( !_clipboard->wait_is_target_available(best_target) ) { - return NULL; + // FIXME: Temporary hack until we add memory input. + // Save the clipboard contents to some file, then read it + gchar *filename = g_build_filename( g_get_tmp_dir(), "inkscape-clipboard-import", NULL ); + + bool file_saved = false; + Glib::ustring target = best_target; + +#ifdef WIN32 + if (best_target == CLIPBOARD_WIN32_EMF_TARGET) + { // Try to save clipboard data as en emf file (using win32 api) + if (OpenClipboard(NULL)) { + HGLOBAL hglb = GetClipboardData(CF_ENHMETAFILE); + if (hglb) { + HENHMETAFILE hemf = CopyEnhMetaFile((HENHMETAFILE) hglb, filename); + if (hemf) { + file_saved = true; + target = CLIPBOARD_WIN32_EMF_MIME; + DeleteEnhMetaFile(hemf); + } + } + CloseClipboard(); + } } +#endif - // doing this synchronously makes better sense - // TODO: use another method because this one is badly broken imo. - // from documentation: "Returns: A SelectionData object, which will be invalid if retrieving the given target failed." - // I don't know how to check whether an object is 'valid' or not, unusable if that's not possible... - Gtk::SelectionData sel = _clipboard->wait_for_contents(best_target); - Glib::ustring target = sel.get_target(); // this can crash if the result was invalid of last function. No way to check for this :( + if (!file_saved) { + if ( !_clipboard->wait_is_target_available(best_target) ) { + return NULL; + } + + // doing this synchronously makes better sense + // TODO: use another method because this one is badly broken imo. + // from documentation: "Returns: A SelectionData object, which will be invalid if retrieving the given target failed." + // I don't know how to check whether an object is 'valid' or not, unusable if that's not possible... + Gtk::SelectionData sel = _clipboard->wait_for_contents(best_target); + target = sel.get_target(); // this can crash if the result was invalid of last function. No way to check for this :( + + // FIXME: Temporary hack until we add memory input. + // Save the clipboard contents to some file, then read it + g_file_set_contents(filename, (const gchar *) sel.get_data(), sel.get_length(), NULL); + } // there is no specific plain SVG input extension, so if we can paste the Inkscape SVG format, // we use the image/svg+xml mimetype to look up the input extension @@ -949,12 +1040,11 @@ SPDocument *ClipboardManagerImpl::_retrieveClipboard(Glib::ustring required_targ if ( in == inlist.end() ) return NULL; // this shouldn't happen unless _getBestTarget returns something bogus - // FIXME: Temporary hack until we add memory input. - // Save the clipboard contents to some file, then read it - gchar *filename = g_build_filename( g_get_tmp_dir(), "inkscape-clipboard-import", NULL ); - g_file_set_contents(filename, (const gchar *) sel.get_data(), sel.get_length(), NULL); - - SPDocument *tempdoc = (*in)->open(filename); + SPDocument *tempdoc = NULL; + try { + tempdoc = (*in)->open(filename); + } catch (...) { + } g_unlink(filename); g_free(filename); @@ -972,26 +1062,61 @@ void ClipboardManagerImpl::_onGet(Gtk::SelectionData &sel, guint /*info*/) { g_assert( _clipboardSPDoc != NULL ); - const Glib::ustring target = sel.get_target(); + Glib::ustring target = sel.get_target(); if(target == "") return; // this shouldn't happen + if (target == CLIPBOARD_TEXT_TARGET) { + target = "image/x-inkscape-svg"; + } + Inkscape::Extension::DB::OutputList outlist; Inkscape::Extension::db.get_output_list(outlist); Inkscape::Extension::DB::OutputList::const_iterator out = outlist.begin(); for ( ; out != outlist.end() && target != (*out)->get_mimetype() ; ++out); - if ( out == outlist.end() ) return; // this also shouldn't happen + if ( out == outlist.end() && target != "image/png") return; // this also shouldn't happen // FIXME: Temporary hack until we add support for memory output. // Save to a temporary file, read it back and then set the clipboard contents gchar *filename = g_build_filename( g_get_tmp_dir(), "inkscape-clipboard-export", NULL ); gsize len; gchar *data; - (*out)->save(_clipboardSPDoc, filename); - g_file_get_contents(filename, &data, &len, NULL); + try { + if (out == outlist.end() && target == "image/png") + { + gdouble dpi = PX_PER_IN; + guint32 bgcolor = 0x00000000; + + Geom::Point origin (SP_ROOT(_clipboardSPDoc->root)->x.computed, SP_ROOT(_clipboardSPDoc->root)->y.computed); + Geom::Rect area = Geom::Rect(origin, origin + sp_document_dimensions(_clipboardSPDoc)); + + unsigned long int width = (unsigned long int) (area.width() * dpi / PX_PER_IN + 0.5); + unsigned long int height = (unsigned long int) (area.height() * dpi / PX_PER_IN + 0.5); + + // read from namedview + Inkscape::XML::Node *nv = sp_repr_lookup_name (_clipboardSPDoc->rroot, "sodipodi:namedview"); + if (nv && nv->attribute("pagecolor")) + bgcolor = sp_svg_read_color(nv->attribute("pagecolor"), 0xffffff00); + if (nv && nv->attribute("inkscape:pageopacity")) + bgcolor |= SP_COLOR_F_TO_U(sp_repr_get_double_attribute (nv, "inkscape:pageopacity", 1.0)); + + sp_export_png_file(_clipboardSPDoc, filename, area, width, height, dpi, dpi, bgcolor, NULL, NULL, true, NULL); + } + else + { + if (!(*out)->loaded()) { + // Need to load the extension. + (*out)->set_state(Inkscape::Extension::Extension::STATE_LOADED); + } + (*out)->save(_clipboardSPDoc, filename); + } + g_file_get_contents(filename, &data, &len, NULL); + + sel.set(8, (guint8 const *) data, len); + } catch (...) { + } + g_unlink(filename); // delete the temporary file g_free(filename); - - sel.set(8, (guint8 const *) data, len); } @@ -1046,17 +1171,17 @@ void ClipboardManagerImpl::_discardInternalClipboard() /** * @brief Get the scale to resize an item, based on the command and desktop state */ -NR::scale ClipboardManagerImpl::_getScale(Geom::Point &min, Geom::Point &max, NR::Rect &obj_rect, bool apply_x, bool apply_y) +Geom::Scale ClipboardManagerImpl::_getScale(Geom::Point const &min, Geom::Point const &max, Geom::Rect const &obj_rect, bool apply_x, bool apply_y) { SPDesktop *desktop = SP_ACTIVE_DESKTOP; double scale_x = 1.0; double scale_y = 1.0; if (apply_x) { - scale_x = (max[Geom::X] - min[Geom::X]) / obj_rect.extent(NR::X); + scale_x = (max[Geom::X] - min[Geom::X]) / obj_rect[Geom::X].extent(); } if (apply_y) { - scale_y = (max[Geom::Y] - min[Geom::Y]) / obj_rect.extent(NR::Y); + scale_y = (max[Geom::Y] - min[Geom::Y]) / obj_rect[Geom::Y].extent(); } // If the "lock aspect ratio" button is pressed and we paste only a single coordinate, // resize the second one by the same ratio too @@ -1065,7 +1190,7 @@ NR::scale ClipboardManagerImpl::_getScale(Geom::Point &min, Geom::Point &max, NR if (apply_y && !apply_x) scale_x = scale_y; } - return NR::scale(scale_x, scale_y); + return Geom::Scale(scale_x, scale_y); } @@ -1090,6 +1215,26 @@ Glib::ustring ClipboardManagerImpl::_getBestTarget() if ( std::find(targets.begin(), targets.end(), *i) != targets.end() ) return *i; } +#ifdef WIN32 + if (OpenClipboard(NULL)) + { // If both bitmap and metafile are present, pick the one that was exported first. + UINT format = EnumClipboardFormats(0); + while (format) { + if (format == CF_ENHMETAFILE || format == CF_DIB || format == CF_BITMAP) + break; + format = EnumClipboardFormats(format); + } + CloseClipboard(); + + if (format == CF_ENHMETAFILE) + return CLIPBOARD_WIN32_EMF_TARGET; + if (format == CF_DIB || format == CF_BITMAP) + return CLIPBOARD_GDK_PIXBUF_TARGET; + } + + if (IsClipboardFormatAvailable(CF_ENHMETAFILE)) + return CLIPBOARD_WIN32_EMF_TARGET; +#endif if (_clipboard->wait_is_image_available()) return CLIPBOARD_GDK_PIXBUF_TARGET; if (_clipboard->wait_is_text_available()) @@ -1107,13 +1252,69 @@ void ClipboardManagerImpl::_setClipboardTargets() Inkscape::Extension::DB::OutputList outlist; Inkscape::Extension::db.get_output_list(outlist); std::list target_list; + bool plaintextSet = false; for (Inkscape::Extension::DB::OutputList::const_iterator out = outlist.begin() ; out != outlist.end() ; ++out) { - target_list.push_back(Gtk::TargetEntry( (*out)->get_mimetype() )); + if ( !(*out)->deactivated() ) { + Glib::ustring mime = (*out)->get_mimetype(); + if (mime != CLIPBOARD_TEXT_TARGET) { + if ( !plaintextSet && (mime.find("svg") == Glib::ustring::npos) ) { + target_list.push_back(Gtk::TargetEntry(CLIPBOARD_TEXT_TARGET)); + plaintextSet = true; + } + target_list.push_back(Gtk::TargetEntry(mime)); + } + } } + // Add PNG export explicitly since there is no extension for this... + // On Windows, GTK will also present this as a CF_DIB/CF_BITMAP + target_list.push_back(Gtk::TargetEntry( "image/png" )); + _clipboard->set(target_list, sigc::mem_fun(*this, &ClipboardManagerImpl::_onGet), sigc::mem_fun(*this, &ClipboardManagerImpl::_onClear)); + +#ifdef WIN32 + // If the "image/x-emf" target handled by the emf extension would be + // presented as a CF_ENHMETAFILE automatically (just like an "image/bmp" + // is presented as a CF_BITMAP) this code would not be needed.. ??? + // Or maybe there is some other way to achieve the same? + + // Note: Metafile is the only format that is rendered and stored in clipboard + // on Copy, all other formats are rendered only when needed by a Paste command. + + // FIXME: This should at least be rewritten to use "delayed rendering". + // If possible make it delayed rendering by using GTK API only. + + if (OpenClipboard(NULL)) { + if ( _clipboardSPDoc != NULL ) { + const Glib::ustring target = CLIPBOARD_WIN32_EMF_MIME; + + Inkscape::Extension::DB::OutputList outlist; + Inkscape::Extension::db.get_output_list(outlist); + Inkscape::Extension::DB::OutputList::const_iterator out = outlist.begin(); + for ( ; out != outlist.end() && target != (*out)->get_mimetype() ; ++out); + if ( out != outlist.end() ) { + // FIXME: Temporary hack until we add support for memory output. + // Save to a temporary file, read it back and then set the clipboard contents + gchar *filename = g_build_filename( g_get_tmp_dir(), "inkscape-clipboard-export.emf", NULL ); + + try { + (*out)->save(_clipboardSPDoc, filename); + HENHMETAFILE hemf = GetEnhMetaFileA(filename); + if (hemf) { + SetClipboardData(CF_ENHMETAFILE, hemf); + DeleteEnhMetaFile(hemf); + } + } catch (...) { + } + g_unlink(filename); // delete the temporary file + g_free(filename); + } + } + CloseClipboard(); + } +#endif }