diff options
author | Thorbjørn Lindeijer <thorbjorn@lindeijer.nl> | 2010-02-25 22:28:13 +0100 |
---|---|---|
committer | Thorbjørn Lindeijer <thorbjorn@lindeijer.nl> | 2010-02-25 23:18:35 +0100 |
commit | d1f7e4f5090ac61142415edaa51f2af86aecc188 (patch) | |
tree | 710c96208bd4ada7f6e19ea6200048b4438c61a2 | |
parent | 861b28494e8c0f8701c093f82f152c3bcdbae9fd (diff) | |
download | mana-d1f7e4f5090ac61142415edaa51f2af86aecc188.tar.gz mana-d1f7e4f5090ac61142415edaa51f2af86aecc188.tar.bz2 mana-d1f7e4f5090ac61142415edaa51f2af86aecc188.tar.xz mana-d1f7e4f5090ac61142415edaa51f2af86aecc188.zip |
Added paste facility from the Wormux project
With CMakeLists.txt adaptions from the Aethyra project.
Reviewed-by: Bernd Wachter
Reviewed-by: Jared Adams
-rw-r--r-- | CMakeLists.txt | 3 | ||||
-rwxr-xr-x | configure.ac | 18 | ||||
-rw-r--r-- | mana.files | 2 | ||||
-rw-r--r-- | src/CMakeLists.txt | 8 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/utils/copynpaste.cpp | 317 | ||||
-rw-r--r-- | src/utils/copynpaste.h | 33 |
7 files changed, 383 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 48e63788..ccd92f84 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,6 +30,9 @@ IF (WIN32) LIST(GET _VERSION 3 VER_BUILD) CONFIGURE_FILE(src/winver.h.in src/winver.h) ELSE (WIN32) + IF (!OSX) + OPTION(USE_X11 "Use X11 Clipboard functionality" ON) + ENDIF (!OSX) SET(PKG_DATADIR ${CMAKE_INSTALL_PREFIX}/share/mana) SET(LOCALEDIR ${CMAKE_INSTALL_PREFIX}/share/locale) SET(PKG_BINDIR ${CMAKE_INSTALL_PREFIX}/bin) diff --git a/configure.ac b/configure.ac index 739b1cb1..54b510d3 100755 --- a/configure.ac +++ b/configure.ac @@ -92,6 +92,24 @@ AC_CHECK_LIB(SDL_gfx, rotozoomSurfaceXY, , AC_MSG_ERROR([ *** Unable to find SDL_gfx library (http://www.ferzkopp.net/joomla/software-mainmenu-14/4-ferzkopps-linux-software/19-sdlgfx)])) AC_CHECK_HEADERS(SDL_rotozoom.h, ,) +# === Check for X11 (check borrowed from Wormux) ======================== +# Deactivated on purpose under OSX (in case X11 SDK is installed) +if test "x$OSX" != "xyes" ; then + AC_CHECK_HEADER(X11/Xlib.h, check_x11="yes",check_x11="no") + if test x${check_x11} = xno ; then + AC_CHECK_HEADER(X11R6/Xlib.h, + [ check_x11="yes" + LDFLAGS="-L/usr/X11R6/include $CFLAGS"], + check_x11="no") + fi + if test x${check_x11} = xyes ; then + AC_CHECK_LIB(X11, XOpenDisplay, + [ LIBS="$LIBS -lX11" + AC_DEFINE(USE_X11, 1, [Define to use X11 copy'n'paste]) ], + []) + fi +fi + # Checks for header files. AC_HEADER_STDC AC_CHECK_HEADERS([arpa/inet.h fcntl.h malloc.h netdb.h netinet/in.h stdlib.h string.h sys/socket.h unistd.h]) @@ -514,6 +514,8 @@ ./src/units.h ./src/utils/base64.cpp ./src/utils/base64.h +./src/utils/copynpaste.cpp +./src/utils/copynpaste.h ./src/utils/dtor.h ./src/utils/gettext.h ./src/utils/mathutils.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index eda28b38..b84e59c6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -55,6 +55,12 @@ IF (WITH_OPENGL) SET(FLAGS "${FLAGS} -DUSE_OPENGL") ENDIF (WITH_OPENGL) +IF (USE_X11) + FIND_PACKAGE(X11 REQUIRED) + INCLUDE_DIRECTORIES(${X11_INCLUDE_DIR}) + SET(FLAGS "${FLAGS} -DUSE_X11") +ENDIF (USE_X11) + INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_SOURCE_DIR} ${SDL_INCLUDE_DIR} @@ -378,6 +384,8 @@ SET(SRCS resources/wallpaper.h utils/base64.cpp utils/base64.h + utils/copynpaste.cpp + utils/copynpaste.h utils/dtor.h utils/gettext.h utils/mathutils.h diff --git a/src/Makefile.am b/src/Makefile.am index bfffef4b..f36fcdf2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -283,6 +283,8 @@ mana_SOURCES = gui/widgets/avatarlistbox.cpp \ resources/wallpaper.h \ utils/base64.cpp \ utils/base64.h \ + utils/copynpaste.cpp \ + utils/copynpaste.h \ utils/dtor.h \ utils/gettext.h \ utils/mathutils.h \ diff --git a/src/utils/copynpaste.cpp b/src/utils/copynpaste.cpp new file mode 100644 index 00000000..9292fb0b --- /dev/null +++ b/src/utils/copynpaste.cpp @@ -0,0 +1,317 @@ +/* + * Retrieve string pasted depending on OS mechanisms. + * Copyright (C) 2001-2010 Wormux Team + * + * This file is part of The Mana Client. + * + * 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 + * 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, see <http://www.gnu.org/licenses/>. + */ + +/* + * IMPORTANT! + * + * This code was taken from Wormux svn trunk at Feb 25 2010. Please don't + * make any unnecessary modifications, and try to sync up modifications + * when possible. + */ + +#ifdef _MSC_VER +# include "msvc/config.h" +#elif defined(HAVE_CONFIG_H) +# include "config.h" +#endif + +#include <SDL_syswm.h> +#include "copynpaste.h" + +#ifdef WIN32 +bool RetrieveBuffer(std::string& text, std::string::size_type& pos) +{ + bool ret = false; + + if (!OpenClipboard(NULL)) + return false; + + HANDLE h = GetClipboardData(CF_UNICODETEXT); + if (h) + { + LPCWSTR data = (LPCWSTR)GlobalLock(h); + + if (data) + { + int len = WideCharToMultiByte(CP_UTF8, 0, data, -1, NULL, 0, NULL, NULL); + if (len > 0) + { + // Convert from UTF-16 to UTF-8 + void *temp = malloc(len); + if (WideCharToMultiByte(CP_UTF8, 0, data, -1, (LPSTR)temp, len, NULL, NULL)) + { + text.insert(pos, (char*)temp); + pos += len-1; + } + free(temp); + ret = true; + } + } + GlobalUnlock(h); + } + else + { + h = GetClipboardData(CF_TEXT); + + if (h) + { + const char *data = (char*)GlobalLock(h); + if (data) + { + text.insert(pos, data); + pos += strlen(data); + ret = true; + } + GlobalUnlock(h); + } + } + + CloseClipboard(); + return ret; +} +#elif defined(__APPLE__) + +#ifdef Status +#undef Status +#endif + +#include <Carbon/Carbon.h> + +// Sorry for the very long code, all nicer OS X APIs are coded in Objective C and not C! +// Also it does very thorough error handling +bool GetDataFromPasteboard( PasteboardRef inPasteboard, char* flavorText /* out */, const int bufSize ) +{ + OSStatus err = noErr; + PasteboardSyncFlags syncFlags; + ItemCount itemCount; + + syncFlags = PasteboardSynchronize( inPasteboard ); + + //require_action( syncFlags & kPasteboardModified, PasteboardOutOfSync, + // err = badPasteboardSyncErr ); + + err = PasteboardGetItemCount( inPasteboard, &itemCount ); + require_noerr( err, CantGetPasteboardItemCount ); + + for (UInt32 itemIndex = 1; itemIndex <= itemCount; itemIndex++) + { + PasteboardItemID itemID; + CFArrayRef flavorTypeArray; + CFIndex flavorCount; + + err = PasteboardGetItemIdentifier( inPasteboard, itemIndex, &itemID ); + require_noerr( err, CantGetPasteboardItemIdentifier ); + + err = PasteboardCopyItemFlavors( inPasteboard, itemID, &flavorTypeArray ); + require_noerr( err, CantCopyPasteboardItemFlavors ); + + flavorCount = CFArrayGetCount( flavorTypeArray ); + + for (CFIndex flavorIndex = 0; flavorIndex < flavorCount; flavorIndex++) + { + CFStringRef flavorType; + CFDataRef flavorData; + CFIndex flavorDataSize; + flavorType = (CFStringRef)CFArrayGetValueAtIndex(flavorTypeArray, flavorIndex); + + // we're only interested by text... + if (UTTypeConformsTo(flavorType, CFSTR("public.utf8-plain-text"))) + { + err = PasteboardCopyItemFlavorData( inPasteboard, itemID, + flavorType, &flavorData ); + require_noerr( err, CantCopyFlavorData ); + flavorDataSize = CFDataGetLength( flavorData ); + flavorDataSize = (flavorDataSize<254) ? flavorDataSize : 254; + + if (flavorDataSize+2 > bufSize) + { + fprintf(stderr, "Cannot copy clipboard, contents is too big!\n"); + return false; + } + + for (short dataIndex = 0; dataIndex <= flavorDataSize; dataIndex++) + { + char byte = *(CFDataGetBytePtr( flavorData ) + dataIndex); + flavorText[dataIndex] = byte; + } + + flavorText[flavorDataSize] = '\0'; + flavorText[flavorDataSize+1] = '\n'; + + CFRelease (flavorData); + return true; + } + + continue; + CantCopyFlavorData: fprintf(stderr, "Cannot copy clipboard, CantCopyFlavorData!\n"); + } + + CFRelease (flavorTypeArray); + continue; + + CantCopyPasteboardItemFlavors: fprintf(stderr, "Cannot copy clipboard, CantCopyPasteboardItemFlavors!\n"); continue; + CantGetPasteboardItemIdentifier: fprintf(stderr, "Cannot copy clipboard, CantGetPasteboardItemIdentifier!\n"); continue; + } + fprintf(stderr, "Cannot copy clipboard, found no acceptable flavour!\n"); + return false; + + CantGetPasteboardItemCount: fprintf(stderr, "Cannot copy clipboard, CantGetPasteboardItemCount!\n"); return false; + //PasteboardOutOfSync: fprintf(stderr, "Cannot copy clipboard, PasteboardOutOfSync!\n"); return false; +} + +bool getClipBoard(char* text /* out */, const int bufSize ) +{ + OSStatus err = noErr; + + PasteboardRef theClipboard; + err = PasteboardCreate( kPasteboardClipboard, &theClipboard ); + require_noerr( err, PasteboardCreateFailed ); + + if (!GetDataFromPasteboard(theClipboard, text, bufSize)) + { + fprintf(stderr, "Cannot copy clipboard, GetDataFromPasteboardFailed!\n"); + return false; + } + + CFRelease(theClipboard); + + return true; + + // ---- error handling + PasteboardCreateFailed: fprintf(stderr, "Cannot copy clipboard, PasteboardCreateFailed!\n"); + CFRelease(theClipboard); + return false; +} + +bool RetrieveBuffer(std::string& text, std::string::size_type& pos) +{ + const int bufSize = 512; + char buffer[bufSize]; + + if (getClipBoard(buffer, bufSize)) + { + text = buffer; + pos += strlen(buffer); + return true; + } + else + { + return false; + } +} + +#elif USE_X11 +static char* getSelection(Display *dpy, Window us, Atom selection) +{ + int max_events = 50; + Window owner = XGetSelectionOwner (dpy, selection); + int ret; + + //printf("XConvertSelection on %s\n", XGetAtomName(dpy, selection)); + if (owner == None) + { + //printf("No owner\n"); + return NULL; + } + XConvertSelection(dpy, selection, XA_STRING, XA_PRIMARY, us, CurrentTime); + XFlush(dpy); + + while (max_events--) + { + XEvent e; + + XNextEvent(dpy, &e); + if(e.type == SelectionNotify) + { + //printf("Received %s\n", XGetAtomName(dpy, e.xselection.selection)); + if(e.xselection.property == None) + { + //printf("Couldn't convert\n"); + return NULL; + } + + long unsigned len, left, dummy; + int format; + Atom type; + unsigned char *data = NULL; + + XGetWindowProperty(dpy, us, e.xselection.property, 0, 0, False, + AnyPropertyType, &type, &format, &len, &left, &data); + if (left < 1) + return NULL; + + ret = XGetWindowProperty(dpy, us, e.xselection.property, 0, left, False, + AnyPropertyType, &type, &format, &len, &dummy, &data); + if (ret != Success) + { + //printf("Failed to get property: %p on %lu\n", data, len); + return NULL; + } + + //printf(">>> Got %s: len=%lu left=%lu (event %i)\n", data, len, left, 50-max_events); + return (char*)data; + } + } + printf("Timeout\n"); + return NULL; +} + +bool RetrieveBuffer(std::string& text, std::string::size_type& pos) +{ + SDL_SysWMinfo info; + + //printf("Retrieving buffer...\n"); + SDL_VERSION(&info.version); + if ( SDL_GetWMInfo(&info) ) + { + Display *dpy = info.info.x11.display; + Window us = info.info.x11.window; + char *data = NULL; + + if (!data) + { + data = getSelection(dpy, us, XA_PRIMARY); + } + if (!data) + { + data = getSelection(dpy, us, XA_SECONDARY); + } + if (!data) + { + Atom XA_CLIPBOARD = XInternAtom(dpy, "CLIPBOARD", 0); + data = getSelection(dpy, us, XA_CLIPBOARD); + } + if (data) + { + // check cursor position + if (pos > text.size()) { + pos = text.size(); + } + + text.insert(pos, data); + pos += strlen(data); + XFree(data); + } + } + return false; +} +#else +bool RetrieveBuffer(std::string&, std::string::size_type&) { return false; } +#endif diff --git a/src/utils/copynpaste.h b/src/utils/copynpaste.h new file mode 100644 index 00000000..1a7c81d0 --- /dev/null +++ b/src/utils/copynpaste.h @@ -0,0 +1,33 @@ +/* + * Retrieve string pasted depending on OS mechanisms. + * Copyright (C) 2001-2010 Wormux Team + * + * This file is part of The Mana Client. + * + * 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 + * 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, see <http://www.gnu.org/licenses/>. + */ + +#include <string> + +/** + * Attempts to retrieve text from the clipboard buffer and inserts it in + * \a text at position \pos. The characters are encoded in utf-8. + * + * Implemented for Windows, X11 and Mac OS X. + * + * @return <code>true</code> when successful or <code>false</code> when there + * was a problem retrieving the clipboard buffer. + */ +bool RetrieveBuffer(std::string& text, std::string::size_type& pos); + |