nasal-props.cxx
NasalPositioned.cxx
NasalCanvas.cxx
+ NasalClipboard.cxx
)
set(HEADERS
NasalSys.hxx
NasalPositioned.hxx
NasalCanvas.hxx
+ NasalClipboard.hxx
)
-
+if(WIN32)
+ list(APPEND SOURCES ClipboardWindows.cxx)
+else()
+ find_package(X11)
+ if(X11_FOUND)
+ list(APPEND SOURCES ClipboardX11.cxx)
+ else()
+ list(APPEND SOURCES ClipboardFallback.cxx)
+ endif()
+endif()
+
flightgear_component(Scripting "${SOURCES}" "${HEADERS}")
--- /dev/null
+// Fallback implementation of clipboard access for Nasal. Copy and edit for
+// implementing support of other platforms
+//
+// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#include "NasalClipboard.hxx"
+
+#include <simgear/debug/logstream.hxx>
+
+
+/**
+ * Provide a basic clipboard whose contents are only available to FlightGear
+ * itself
+ */
+class ClipboardFallback:
+ public NasalClipboard
+{
+ public:
+
+ /**
+ * Get clipboard contents as text
+ */
+ virtual std::string getText(Type type)
+ {
+ return type == CLIPBOARD ? _clipboard : _selection;
+ }
+
+ /**
+ * Set clipboard contents as text
+ */
+ virtual bool setText(const std::string& text, Type type)
+ {
+ if( type == CLIPBOARD )
+ _clipboard = text;
+ else
+ _selection = text;
+ return true;
+ }
+
+ protected:
+
+ std::string _clipboard,
+ _selection;
+};
+
+//------------------------------------------------------------------------------
+NasalClipboard::Ptr NasalClipboard::create()
+{
+ return NasalClipboard::Ptr(new ClipboardFallback);
+}
--- /dev/null
+// Windows implementation of clipboard access for Nasal
+//
+// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#include "NasalClipboard.hxx"
+
+#include <simgear/debug/logstream.hxx>
+#include <windows.h>
+
+/**
+ * Windows does only support on clipboard and no selection. We fake also the X11
+ * selection buffer - at least inside FlightGear
+ */
+class ClipboardWindows:
+ public NasalClipboard
+{
+ public:
+
+ /**
+ * Get clipboard contents as text
+ */
+ virtual std::string getText(Type type)
+ {
+ if( type == CLIPBOARD )
+ {
+ std::string data;
+
+ if( !OpenClipboard(NULL) )
+ return data;
+
+ HANDLE hData = GetClipboardData( CF_TEXT );
+ char* buff = (char*)GlobalLock( hData );
+ if (buff)
+ data = buff;
+ GlobalUnlock( hData );
+ CloseClipboard();
+
+ return data;
+ }
+ else
+ return _selection;
+ }
+
+ /**
+ * Set clipboard contents as text
+ */
+ virtual bool setText(const std::string& text, Type type)
+ {
+ if( type == CLIPBOARD )
+ {
+ if( !OpenClipboard(NULL) )
+ return false;
+
+ bool ret = true;
+ if( !EmptyClipboard() )
+ ret = false;
+ else if( !text.empty() )
+ {
+ HGLOBAL hGlob = GlobalAlloc(GMEM_MOVEABLE, text.size() + 1);
+ if( !hGlob )
+ ret = false;
+ else
+ {
+ memcpy(GlobalLock(hGlob), (char*)&text[0], text.size() + 1);
+ GlobalUnlock(hGlob);
+
+ if( !SetClipboardData(CF_TEXT, hGlob) )
+ {
+ GlobalFree(hGlob);
+ ret = false;
+ }
+ }
+ }
+
+ CloseClipboard();
+ return ret;
+ }
+ else
+ {
+ _selection = text;
+ return true;
+ }
+ }
+
+ protected:
+
+ std::string _selection;
+};
+
+//------------------------------------------------------------------------------
+NasalClipboard::Ptr NasalClipboard::create()
+{
+ return NasalClipboard::Ptr(new ClipboardWindows);
+}
--- /dev/null
+// X11 implementation of clipboard access for Nasal
+//
+// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#include "NasalClipboard.hxx"
+
+#include <simgear/debug/logstream.hxx>
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+
+class ClipboardX11:
+ public NasalClipboard
+{
+ public:
+ ClipboardX11():
+ _display( XOpenDisplay(NULL) ),
+ _window( XCreateSimpleWindow(
+ _display,
+ DefaultRootWindow(_display),
+ 0, 0, 1, 1, // dummy dimensions -> window will never be mapped
+ 0,
+ 0, 0
+ ) ),
+ _atom_targets( XInternAtom(_display, "TARGETS", False) ),
+ _atom_primary( XInternAtom(_display, "PRIMARY", False) ),
+ _atom_clipboard( XInternAtom(_display, "CLIPBOARD", False) )
+ {
+ assert(_display);
+ assert(_atom_targets != None);
+ assert(_atom_primary != None);
+ assert(_atom_clipboard != None);
+ }
+
+ /**
+ * Get clipboard contents as text
+ */
+ virtual std::string getText(Type type)
+ {
+ Atom atom_type = (type == CLIPBOARD ? _atom_clipboard : _atom_primary);
+
+ //Request a list of possible conversions
+ XConvertSelection( _display, atom_type, _atom_targets, atom_type,
+ _window, CurrentTime );
+ XFlush(_display);
+
+ Atom requested_type = None;
+ bool sent_request = false;
+
+ for(int cnt = 0; cnt < 5;)
+ {
+ XEvent event;
+ XNextEvent(_display, &event);
+
+ if( event.type == SelectionNotify )
+ {
+ Atom target = event.xselection.target;
+ if(event.xselection.property == None)
+ {
+ if( target == _atom_targets )
+ // If TARGETS can not be converted no selection is available
+ break;
+
+ SG_LOG
+ (
+ SG_NASAL,
+ SG_WARN,
+ "ClipboardX11::getText: Conversion failed: "
+ "target=" << getAtomName(target)
+ );
+ break;
+ }
+ else
+ {
+ //If we're being given a list of targets (possible conversions)
+ if(target == _atom_targets && !sent_request)
+ {
+ sent_request = true;
+ requested_type = XA_STRING; // TODO select other type
+ XConvertSelection( _display, atom_type, requested_type, atom_type,
+ _window, CurrentTime );
+ }
+ else if(target == requested_type)
+ {
+ Property prop = readProperty(_window, atom_type);
+ if( prop.format != 8 )
+ {
+ SG_LOG
+ (
+ SG_NASAL,
+ SG_WARN,
+ "ClipboardX11::getText: can only handle 8-bit data (is "
+ << prop.format << "-bit) -> retry "
+ << cnt++
+ );
+ XFree(prop.data);
+ continue;
+ }
+
+ std::string result((const char*)prop.data, prop.num_items);
+ XFree(prop.data);
+
+ return result;
+ }
+ else
+ {
+ SG_LOG
+ (
+ SG_NASAL,
+ SG_WARN,
+ "ClipboardX11::getText: wrong target: " << getAtomName(target)
+ );
+ break;
+ }
+ }
+ }
+ else
+ {
+ SG_LOG
+ (
+ SG_NASAL,
+ SG_WARN,
+ "ClipboardX11::getText: unexpected XEvent: " << event.type
+ );
+ break;
+ }
+ }
+
+ return std::string();
+ }
+
+ /**
+ * Set clipboard contents as text
+ */
+ virtual bool setText(const std::string& text, Type type)
+ {
+ SG_LOG
+ (
+ SG_NASAL,
+ SG_ALERT,
+ "ClipboardX11::setText: not yet implemented!"
+ );
+ return false;
+ }
+
+ protected:
+
+ Display *_display;
+ Window _window;
+ Atom _atom_targets,
+ _atom_primary,
+ _atom_clipboard;
+
+ struct Property
+ {
+ unsigned char *data;
+ int format, num_items;
+ Atom type;
+ };
+
+ // Get all data from a property
+ Property readProperty(Window w, Atom property)
+ {
+ Atom actual_type;
+ int actual_format;
+ unsigned long nitems;
+ unsigned long bytes_after;
+ unsigned char *ret=0;
+
+ int read_bytes = 1024;
+
+ //Keep trying to read the property until there are no
+ //bytes unread.
+ do
+ {
+ if( ret )
+ XFree(ret);
+
+ XGetWindowProperty
+ (
+ _display, w, property, 0, read_bytes, False, AnyPropertyType,
+ &actual_type, &actual_format, &nitems, &bytes_after,
+ &ret
+ );
+
+ read_bytes *= 2;
+ } while( bytes_after );
+
+ Property p = {ret, actual_format, nitems, actual_type};
+ return p;
+ }
+
+ std::string getAtomName(Atom atom)
+ {
+ return atom == None ? "None" : XGetAtomName(_display, atom);
+ }
+
+};
+
+//------------------------------------------------------------------------------
+NasalClipboard::Ptr NasalClipboard::create()
+{
+ return NasalClipboard::Ptr(new ClipboardX11);
+}
--- /dev/null
+// X11 implementation of clipboard access for Nasal
+//
+// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "NasalClipboard.hxx"
+#include "NasalSys.hxx"
+
+#include <boost/algorithm/string/case_conv.hpp>
+#include <cstddef>
+
+/*
+ * Nasal wrappers for setting/getting clipboard text
+ */
+//------------------------------------------------------------------------------
+static NasalClipboard::Type parseType(naContext c, int argc, naRef* args, int i)
+{
+ if( argc > i )
+ {
+ if( !naIsString(args[i]) )
+ naRuntimeError(c, "clipboard: invalid arg (not a string)");
+
+ std::string type_str( naStr_data(args[i]) );
+ boost::to_upper(type_str);
+
+ if( type_str == "CLIPBOARD" )
+ return NasalClipboard::CLIPBOARD;
+ else if( type_str == "PRIMARY" || type_str == "SELECTION" )
+ return NasalClipboard::PRIMARY;
+ else
+ naRuntimeError(c, "clipboard: unknown clipboard type");
+ }
+
+ return NasalClipboard::CLIPBOARD;
+}
+
+//------------------------------------------------------------------------------
+static naRef f_setClipboardText(naContext c, naRef me, int argc, naRef* args)
+{
+ if( argc < 1 || argc > 2 )
+ naRuntimeError( c, "clipboard.setText() expects 1 or 2 arguments: "
+ "text, [, type = \"CLIPBOARD\"]" );
+
+ if( !naIsString(args[0]) )
+ naRuntimeError(c, "clipboard.setText() invalid arg (arg 0 not a string)");
+
+ return
+ naNum
+ (
+ NasalClipboard::getInstance()->setText( naStr_data(args[0]),
+ parseType(c, argc, args, 1) )
+ );
+}
+
+//------------------------------------------------------------------------------
+static naRef f_getClipboardText(naContext c, naRef me, int argc, naRef* args)
+{
+ if( argc > 1 )
+ naRuntimeError(c, "clipboard.getText() accepts max 1 arg: "
+ "[type = \"CLIPBOARD\"]" );
+
+ const std::string& text =
+ NasalClipboard::getInstance()->getText(parseType(c, argc, args, 0));
+
+ // TODO create some nasal helper functions (eg. stringToNasal)
+ // some functions are available spread over different files (eg.
+ // NasalPositioned.cxx)
+ return naStr_fromdata(naNewString(c), text.c_str(), text.length());
+}
+
+//------------------------------------------------------------------------------
+// Table of extension functions, terminate with 0,0
+static struct {const char* name; naCFunction func; } funcs[] = {
+ { "setText", f_setClipboardText },
+ { "getText", f_getClipboardText },
+ { 0,0 } // TERMINATION
+};
+
+//------------------------------------------------------------------------------
+NasalClipboard::Ptr NasalClipboard::_clipboard;
+naRef NasalClipboard::_clipboard_hash;
+
+//------------------------------------------------------------------------------
+NasalClipboard::~NasalClipboard()
+{
+
+}
+
+//------------------------------------------------------------------------------
+void NasalClipboard::init(FGNasalSys *nasal)
+{
+ _clipboard = create();
+ _clipboard_hash = naNewHash(nasal->context());
+
+ nasal->globalsSet("clipboard", _clipboard_hash);
+
+ for(size_t i=0;funcs[i].name;i++)
+ {
+ nasal->hashset
+ (
+ _clipboard_hash,
+ funcs[i].name,
+ naNewFunc(nasal->context(), naNewCCode(nasal->context(), funcs[i].func))
+ );
+
+ SG_LOG(SG_NASAL, SG_DEBUG, "Adding clipboard function: " << funcs[i].name );
+ }
+}
+
+//------------------------------------------------------------------------------
+NasalClipboard::Ptr NasalClipboard::getInstance()
+{
+ return _clipboard;
+}
--- /dev/null
+// Clipboard access for Nasal
+//
+// Copyright (C) 2012 Thomas Geymayer <tomgey@gmail.com>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#ifndef NASAL_CLIPOARD_HXX_
+#define NASAL_CLIPOARD_HXX_
+
+#include <simgear/nasal/nasal.h>
+#include <boost/shared_ptr.hpp>
+#include <string>
+
+class FGNasalSys;
+class NasalClipboard
+{
+ public:
+
+ enum Type
+ {
+ /// Standard clipboard as supported by nearly all operating systems
+ CLIPBOARD,
+
+ /// X11 platforms support also a mode called PRIMARY selection which
+ /// contains the current (mouse) selection and can typically be inserted
+ /// via a press on the middle mouse button
+ PRIMARY
+ };
+
+ typedef boost::shared_ptr<NasalClipboard> Ptr;
+
+ virtual std::string getText(Type type = CLIPBOARD) = 0;
+ virtual bool setText( const std::string& text,
+ Type type = CLIPBOARD ) = 0;
+
+ /**
+ * Sets up the clipboard and puts all the extension functions into a new
+ * "clipboard" namespace.
+ */
+ static void init(FGNasalSys *nasal);
+
+ /**
+ * Get clipboard platform specific instance
+ */
+ static Ptr getInstance();
+
+ protected:
+
+ static Ptr _clipboard;
+ static naRef _clipboard_hash;
+
+ /**
+ * Implementation supplied by actual platform implementation
+ */
+ static Ptr create();
+
+ virtual ~NasalClipboard() = 0;
+};
+
+#endif /* NASAL_CLIPOARD_HXX_ */
#include "NasalSys.hxx"
#include "NasalPositioned.hxx"
#include "NasalCanvas.hxx"
+#include "NasalClipboard.hxx"
#include <Main/globals.hxx>
#include <Main/util.hxx>
#include <Main/fg_props.hxx>
+
using std::map;
static FGNasalSys* nasalSys = 0;
_callCount = 0;
}
+// Utility. Sets a named key in a hash by C string, rather than nasal
+// string object.
+void FGNasalSys::hashset(naRef hash, const char* key, naRef val)
+{
+ naRef s = naNewString(_context);
+ naStr_fromdata(s, (char*)key, strlen(key));
+ naHash_set(hash, s, val);
+}
+
+void FGNasalSys::globalsSet(const char* key, naRef val)
+{
+ hashset(_globals, key, val);
+}
+
naRef FGNasalSys::call(naRef code, int argc, naRef* args, naRef locals)
{
return callMethod(code, naNil(), argc, args, locals);
return script;
}
-// Utility. Sets a named key in a hash by C string, rather than nasal
-// string object.
-void FGNasalSys::hashset(naRef hash, const char* key, naRef val)
-{
- naRef s = naNewString(_context);
- naStr_fromdata(s, (char*)key, strlen(key));
- naHash_set(hash, s, val);
-}
-
// The get/setprop functions accept a *list* of strings and walk
// through the property tree with them to find the appropriate node.
// This allows a Nasal object to hold onto a property path and use it
initNasalPositioned(_globals, _context, _gcHash);
initNasalCanvas(_globals, _context, _gcHash);
-
+ NasalClipboard::init(this);
+
// Now load the various source files in the Nasal directory
simgear::Dir nasalDir(SGPath(globals->get_fg_root(), "Nasal"));
loadScriptDirectory(nasalDir);
void deleteModule(const char* moduleName);
+ /**
+ * Set member of specified hash to given value
+ */
+ void hashset(naRef hash, const char* key, naRef val);
+
+ /**
+ * Set member of globals hash to given value
+ */
+ void globalsSet(const char* key, naRef val);
+
naRef call(naRef code, int argc, naRef* args, naRef locals);
naRef callMethod(naRef code, naRef self, int argc, naRef* args, naRef locals);
void loadPropertyScripts(SGPropertyNode* n);
void loadScriptDirectory(simgear::Dir nasalDir);
void addModule(string moduleName, simgear::PathList scripts);
- void hashset(naRef hash, const char* key, naRef val);
void logError(naContext);
naRef parse(const char* filename, const char* buf, int len);
naRef genPropsModule();