From fdcad184f9c5a9837a9566b137080d3310c862d1 Mon Sep 17 00:00:00 2001 From: Eduardo Bart Date: Tue, 8 Jan 2013 18:45:27 -0200 Subject: [PATCH] Fix platform issues regarding charsets * IMPORTANT: A new dependency is required, boost_locale, comes with boost 1.50.0 or later * Copying and pasting special characters should now work * Running otclient from filepaths with special characters should work now too --- src/framework/CMakeLists.txt | 27 +++-- src/framework/core/application.cpp | 36 ++++-- src/framework/core/application.h | 2 +- src/framework/core/graphicalapplication.cpp | 20 ++-- src/framework/core/graphicalapplication.h | 2 +- src/framework/core/logger.cpp | 34 +++++- src/framework/luaengine/luaexception.cpp | 2 +- src/framework/platform/win32window.cpp | 123 ++++++++++---------- src/framework/platform/win32window.h | 2 +- src/framework/platform/x11window.cpp | 94 +++++++-------- src/framework/platform/x11window.h | 4 +- src/framework/stdext/string.cpp | 64 +++++----- src/framework/stdext/string.h | 9 +- 13 files changed, 238 insertions(+), 181 deletions(-) diff --git a/src/framework/CMakeLists.txt b/src/framework/CMakeLists.txt index 5c2f05fe..18609330 100644 --- a/src/framework/CMakeLists.txt +++ b/src/framework/CMakeLists.txt @@ -143,18 +143,18 @@ else() endif() # gcc compile flags -set(WARNS_FLAGS "-Wall -Wextra -Werror -Wno-unused-parameter -Wno-unused-but-set-variable -Wno-unused-variable") +set(WARNS_FLAGS "-Wall -Wextra -Werror -Wno-unused-parameter -Wno-unused-but-set-variable -Wno-unused-variable -Wno-unused-result") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNS_FLAGS} ${ARCH_FLAGS} ${CPP2011_FLAGS} -pipe") set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O1 -g -fno-omit-frame-pointer") set(CMAKE_CXX_FLAGS_RELEASE "-O2") -set(CMAKE_CXX_FLAGS_PERFORMANCE "-Ofast -mmmx -msse -msse2") set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os") +set(CMAKE_CXX_FLAGS_PERFORMANCE "-Ofast -mmmx -msse -msse2") # process options if(USE_STATIC_LIBS) if(NOT APPLE) - set(CMAKE_CXX_LINK_FLAGS "-static-libgcc -static-libstdc++") + set(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -static-libgcc -static-libstdc++") endif() message(STATUS "Link to static libraries: ON") else() @@ -169,7 +169,7 @@ message(STATUS "Build revision: ${BUILD_REVISION}") add_definitions(-D"BUILD_REVISION=\\\"${BUILD_REVISION}\\\"") # find boost -set(REQUIRED_BOOST_COMPONENTS system filesystem) +set(REQUIRED_BOOST_COMPONENTS system filesystem regex locale) if(WIN32) set(Boost_THREADAPI win32) set(framework_DEFINITIONS ${framework_DEFINITIONS} -DBOOST_THREAD_USE_LIB) # fix boost thread linkage @@ -177,7 +177,7 @@ if(WIN32) endif() set(Boost_USE_MULTITHREADED ON) set(Boost_USE_STATIC_LIBS ${USE_STATIC_LIBS}) -find_package(Boost 1.46.0 COMPONENTS ${REQUIRED_BOOST_COMPONENTS} REQUIRED) +find_package(Boost 1.50.0 COMPONENTS ${REQUIRED_BOOST_COMPONENTS} REQUIRED) #find lua if(LUAJIT) @@ -232,12 +232,15 @@ if(WIN32) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mthreads") set(framework_DEFINITIONS ${framework_DEFINITIONS} -D_WIN32_WINNT=0x0501) set(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -Wl,--large-address-aware") # strip all debug information + set(SYSTEM_LIBRARIES "") elseif(APPLE) set(framework_DEFINITIONS ${framework_DEFINITIONS} -D_REENTRANT) # enable thread safe code + set(SYSTEM_LIBRARIES "") else() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread") - set(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -rdynamic") # rdynamic is needed by backtrace.h used in crash handler - set(framework_LIBRARIES ${framework_LIBRARIES} dl) + set(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} -rdynamic -Wl,-rpath,./libs") # rdynamic is needed by backtrace.h used in crash handler + set(SYSTEM_LIBRARIES dl) + set(framework_LIBRARIES ${framework_LIBRARIES} ${SYSTEM_LIBRARIES}) endif() if(FRAMEWORK_GRAPHICS) @@ -375,6 +378,10 @@ if(FRAMEWORK_GRAPHICS) ${CMAKE_CURRENT_LIST_DIR}/platform/win32window.h ${CMAKE_CURRENT_LIST_DIR}/platform/x11window.cpp ${CMAKE_CURRENT_LIST_DIR}/platform/x11window.h + ${CMAKE_CURRENT_LIST_DIR}/platform/win32platform.cpp + ${CMAKE_CURRENT_LIST_DIR}/platform/unixplatform.cpp + ${CMAKE_CURRENT_LIST_DIR}/platform/platform.cpp + ${CMAKE_CURRENT_LIST_DIR}/platform/platform.h # window input ${CMAKE_CURRENT_LIST_DIR}/input/mouse.cpp @@ -430,8 +437,12 @@ endif() if(FRAMEWORK_NET) if(WIN32) - set(framework_LIBRARIES ${framework_LIBRARIES} ws2_32 mswsock) + set(NET_LIBRARIES ws2_32 mswsock) + else() + set(NET_LIBRARIES "") endif() + set(framework_LIBRARIES ${framework_LIBRARIES} ${NET_LIBRARIES}) + set(framework_SOURCES ${framework_SOURCES} ${CMAKE_CURRENT_LIST_DIR}/net/connection.cpp ${CMAKE_CURRENT_LIST_DIR}/net/connection.h diff --git a/src/framework/core/application.cpp b/src/framework/core/application.cpp index 574b1113..eb17ce96 100644 --- a/src/framework/core/application.cpp +++ b/src/framework/core/application.cpp @@ -29,26 +29,24 @@ #include #include #include +#include + +#include +#include +#include +#include #ifdef FW_NET #include #endif -/* Ugly hack but works. */ -#if defined __APPLE__ && defined CRASH_HANDLER -/* UNIX Crash handler for some reason did not go as expected on a Mac system - * TODO: RTFM it. - */ -#undef CRASH_HANDLER -#endif - void exitSignalHandler(int sig) { static bool signaled = false; switch(sig) { case SIGTERM: case SIGINT: - if(!signaled) { + if(!signaled && !g_app.isStopping() && !g_app.isTerminated()) { signaled = true; g_dispatcher.addEvent(std::bind(&Application::close, &g_app)); } @@ -65,7 +63,7 @@ Application::Application() m_stopping = false; } -void Application::init(const std::vector& args) +void Application::init(std::vector& args) { // capture exit signals signal(SIGTERM, exitSignalHandler); @@ -75,6 +73,15 @@ void Application::init(const std::vector& args) installCrashHandler(); #endif + // setup locale + boost::locale::generator locgen; + std::locale::global(locgen.generate("")); + std::locale utf8Loc = locgen.generate("en_US.UTF-8"); + boost::filesystem::path::imbue(utf8Loc); + + // process args encoding + g_platform.processArgs(args); + std::string startupOptions; for(uint i=1;i& args); + virtual void init(std::vector& args); virtual void deinit(); virtual void terminate(); virtual void run() = 0; diff --git a/src/framework/core/graphicalapplication.cpp b/src/framework/core/graphicalapplication.cpp index dc2914e1..cf6c72f3 100644 --- a/src/framework/core/graphicalapplication.cpp +++ b/src/framework/core/graphicalapplication.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #ifdef FW_SOUND @@ -36,7 +37,7 @@ GraphicalApplication g_app; -void GraphicalApplication::init(const std::vector& args) +void GraphicalApplication::init(std::vector& args) { Application::init(args); @@ -78,14 +79,14 @@ void GraphicalApplication::terminate() // destroy any remaining widget g_ui.terminate(); + Application::terminate(); + m_terminated = false; + #ifdef FW_SOUND // terminate sound g_sounds.terminate(); #endif - Application::terminate(); - m_terminated = false; - // terminate graphics m_foreground = nullptr; g_graphics.terminate(); @@ -106,16 +107,21 @@ void GraphicalApplication::run() poll(); g_clock.update(); - g_lua.callGlobalField("g_app", "onRun"); - + // show window g_window.show(); + // run the second poll + poll(); + g_clock.update(); + + g_lua.callGlobalField("g_app", "onRun"); + while(!m_stopping) { // poll all events before rendering poll(); if(g_window.isVisible()) { - // the otclient's screen consists of two panes + // the screen consists of two panes // background pane - high updated and animated pane (where the game are stuff happens) // foreground pane - steady pane with few animated stuff (UI) bool redraw = false; diff --git a/src/framework/core/graphicalapplication.h b/src/framework/core/graphicalapplication.h index 93e902da..73cbec49 100644 --- a/src/framework/core/graphicalapplication.h +++ b/src/framework/core/graphicalapplication.h @@ -35,7 +35,7 @@ class GraphicalApplication : public Application }; public: - void init(const std::vector< std::string >& args); + void init(std::vector& args); void deinit(); void terminate(); void run(); diff --git a/src/framework/core/logger.cpp b/src/framework/core/logger.cpp index 916988aa..5308ad57 100644 --- a/src/framework/core/logger.cpp +++ b/src/framework/core/logger.cpp @@ -23,8 +23,12 @@ #include "logger.h" #include "eventdispatcher.h" +#include +#include + #ifdef FW_GRAPHICS #include +#include #endif Logger g_logger; @@ -43,6 +47,21 @@ void Logger::log(Fw::LogLevel level, const std::string& message) const static std::string logPrefixes[] = { "", "", "WARNING: ", "ERROR: ", "FATAL ERROR: " }; std::string outmsg = logPrefixes[level] + message; + +#if !defined(NDEBUG) && !defined(WIN32) + // replace paths for improved debug with vim + std::stringstream tmp; + boost::smatch m; + boost::regex e ("/[^ :]+"); + while(boost::regex_search(outmsg,m,e)) { + tmp << m.prefix().str(); + tmp << g_resources.getRealDir(m.str()) << m.str(); + outmsg = m.suffix().str(); + } + if(!tmp.str().empty()) + outmsg = tmp.str(); +#endif + std::cout << outmsg << std::endl; if(m_outFile.good()) { @@ -74,16 +93,21 @@ void Logger::log(Fw::LogLevel level, const std::string& message) void Logger::logFunc(Fw::LogLevel level, const std::string& message, std::string prettyFunction) { - std::stringstream ss; prettyFunction = prettyFunction.substr(0, prettyFunction.find_first_of('(')); if(prettyFunction.find_last_of(' ') != std::string::npos) prettyFunction = prettyFunction.substr(prettyFunction.find_last_of(' ') + 1); - if(!prettyFunction.empty()) - ss << "[" << prettyFunction << "] "; - ss << message; - log(level, ss.str()); + std::string out = message; + + if(!prettyFunction.empty()) { + if(g_lua.isInCppCallback()) + out = g_lua.traceback(out, 1); + else + out += "\nat:\t[C++]: " + prettyFunction; + } + + log(level, out); } void Logger::fireOldMessages() diff --git a/src/framework/luaengine/luaexception.cpp b/src/framework/luaengine/luaexception.cpp index d5cacae5..29c7a257 100644 --- a/src/framework/luaengine/luaexception.cpp +++ b/src/framework/luaengine/luaexception.cpp @@ -35,7 +35,7 @@ void LuaException::generateLuaErrorMessage(const std::string& error, int traceLe if(traceLevel >= 0) m_what = stdext::format("LUA ERROR: %s", g_lua.traceback(error, traceLevel)); else - m_what = stdext::format("LUA ERROR: %s", error); + m_what = stdext::format("LUA ERROR:\n%s", error); } LuaBadNumberOfArgumentsException::LuaBadNumberOfArgumentsException(int expected, int got) diff --git a/src/framework/platform/win32window.cpp b/src/framework/platform/win32window.cpp index dc38e756..96b08d4d 100644 --- a/src/framework/platform/win32window.cpp +++ b/src/framework/platform/win32window.cpp @@ -23,9 +23,8 @@ #ifdef WIN32 #include "win32window.h" - +#include #include -#include #include #define HSB_BIT_SET(p, n) (p[(n)/8] |= (128 >>((n)%8))) @@ -767,37 +766,33 @@ void WIN32Window::hideMouse() void WIN32Window::displayFatalError(const std::string& message) { - MessageBoxA(m_window, message.c_str(), "FATAL ERROR", MB_OK | MB_ICONERROR); + MessageBoxW(m_window, stdext::latin1_to_utf16(message).c_str(), L"FATAL ERROR", MB_OK | MB_ICONERROR); } void WIN32Window::setMouseCursor(const std::string& file, const Point& hotSpot) { - std::stringstream fin; - g_resources.loadFile(file, fin); + ImagePtr image = Image::load(file); - apng_data apng; - if(load_apng(fin, &apng) != 0) { - g_logger.traceError(stdext::format("unable to load png file %s", file)); + if(!image) { + g_logger.traceError(stdext::format("unable to load cursor image file %s", file)); return; } - if(apng.bpp != 4) { - g_logger.error("the cursor png must have 4 channels"); - free_apng(&apng); + if(image->getBpp() != 4) { + g_logger.error("the cursor image must have 4 channels"); return; } - if(apng.width != 32|| apng.height != 32) { - g_logger.error("the cursor png must have 32x32 dimension"); - free_apng(&apng); + if(image->getWidth() != 32 || image->getHeight() != 32) { + g_logger.error("the cursor image must have 32x32 dimension"); return; } if(m_cursor != NULL) DestroyCursor(m_cursor); - int width = apng.width; - int height = apng.height; + int width = image->getWidth(); + int height = image->getHeight(); int numbits = width * height; int numbytes = (width * height)/8; @@ -805,14 +800,13 @@ void WIN32Window::setMouseCursor(const std::string& file, const Point& hotSpot) std::vector xorMask(numbytes, 0); for(int i=0;igetPixelData() + i*4); if(rgba == 0xffffffff) { //white HSB_BIT_SET(xorMask, i); } else if(rgba == 0x00000000) { //alpha HSB_BIT_SET(andMask, i); } // otherwise 0xff000000 => black } - free_apng(&apng); m_cursor = CreateCursor(m_instance, hotSpot.x, hotSpot.y, width, height, &andMask[0], &xorMask[0]); SetCursor(m_cursor); @@ -820,7 +814,7 @@ void WIN32Window::setMouseCursor(const std::string& file, const Point& hotSpot) void WIN32Window::setTitle(const std::string& title) { - SetWindowTextA(m_window, title.c_str()); + SetWindowTextW(m_window, stdext::latin1_to_utf16(title).c_str()); } void WIN32Window::setMinimumSize(const Size& minimumSize) @@ -868,47 +862,46 @@ void WIN32Window::setVerticalSync(bool enable) #endif } -void WIN32Window::setIcon(const std::string& pngIcon) +void WIN32Window::setIcon(const std::string& file) { - apng_data apng; - std::stringstream fin; - g_resources.loadFile(pngIcon, fin); - if(load_apng(fin, &apng) == 0) { - if(apng.bpp != 4) { - g_logger.error("could not set app icon, icon image must have 4 channels"); - free_apng(&apng); - } + ImagePtr image = Image::load(file); - int n = apng.width * apng.height; - std::vector iconData(n); - for(int i=0; i < n;++i) { - uint8 *pixel = (uint8*)&iconData[i]; - pixel[2] = *(apng.pdata + (i * 4) + 0); - pixel[1] = *(apng.pdata + (i * 4) + 1); - pixel[0] = *(apng.pdata + (i * 4) + 2); - pixel[3] = *(apng.pdata + (i * 4) + 3); - } + if(!image) { + g_logger.traceError(stdext::format("unable to load icon file %s", file)); + return; + } - HBITMAP hbmColor = CreateBitmap(apng.width, apng.height, 1, 32, &iconData[0]); - HBITMAP hbmMask = CreateCompatibleBitmap(GetDC(NULL), apng.width, apng.height); + if(image->getBpp() != 4) { + g_logger.error("the app icon must have 4 channels"); + return; + } - ICONINFO ii; - ii.fIcon = TRUE; - ii.hbmColor = hbmColor; - ii.hbmMask = hbmMask; - ii.xHotspot = 0; - ii.yHotspot = 0; + int n = image->getWidth() * image->getHeight(); + std::vector iconData(n); + for(int i=0; i < n;++i) { + uint8 *pixel = (uint8*)&iconData[i]; + pixel[2] = *(image->getPixelData() + (i * 4) + 0); + pixel[1] = *(image->getPixelData() + (i * 4) + 1); + pixel[0] = *(image->getPixelData() + (i * 4) + 2); + pixel[3] = *(image->getPixelData() + (i * 4) + 3); + } - HICON icon = CreateIconIndirect(&ii); - DeleteObject(hbmMask); - DeleteObject(hbmColor); + HBITMAP hbmColor = CreateBitmap(image->getWidth(), image->getHeight(), 1, 32, &iconData[0]); + HBITMAP hbmMask = CreateCompatibleBitmap(GetDC(NULL), image->getWidth(), image->getHeight()); - SendMessage(m_window, WM_SETICON, ICON_SMALL, (LPARAM)icon); - SendMessage(m_window, WM_SETICON, ICON_BIG, (LPARAM)icon); + ICONINFO ii; + ii.fIcon = TRUE; + ii.hbmColor = hbmColor; + ii.hbmMask = hbmMask; + ii.xHotspot = 0; + ii.yHotspot = 0; - free_apng(&apng); - } else - g_logger.error("could not load app icon"); + HICON icon = CreateIconIndirect(&ii); + DeleteObject(hbmMask); + DeleteObject(hbmColor); + + SendMessage(m_window, WM_SETICON, ICON_SMALL, (LPARAM)icon); + SendMessage(m_window, WM_SETICON, ICON_BIG, (LPARAM)icon); } void WIN32Window::setClipboardText(const std::string& text) @@ -916,17 +909,19 @@ void WIN32Window::setClipboardText(const std::string& text) if(!OpenClipboard(m_window)) return; - HGLOBAL hglb = GlobalAlloc(GMEM_MOVEABLE, (text.length() + 1) * sizeof(TCHAR)); + HGLOBAL hglb = GlobalAlloc(GMEM_MOVEABLE, (text.length() + 1) * sizeof(WCHAR)); if(!hglb) return; - LPTSTR lptstr = (LPTSTR)GlobalLock(hglb); - memcpy(lptstr, &text[0], text.length() * sizeof(TCHAR)); - lptstr[text.length()] = (TCHAR)0; + std::wstring wtext = stdext::latin1_to_utf16(text); + + LPWSTR lpwstr = (LPWSTR)GlobalLock(hglb); + memcpy(lpwstr, (char*)&wtext[0], wtext.length() * sizeof(WCHAR)); + lpwstr[text.length()] = (WCHAR)0; GlobalUnlock(hglb); EmptyClipboard(); - SetClipboardData(CF_TEXT, hglb); + SetClipboardData(CF_UNICODETEXT, hglb); CloseClipboard(); } @@ -942,11 +937,11 @@ std::string WIN32Window::getClipboardText() if(!OpenClipboard(m_window)) return text; - HGLOBAL hglb = GetClipboardData(CF_TEXT); + HGLOBAL hglb = GetClipboardData(CF_UNICODETEXT); if(hglb) { - LPTSTR lptstr = (LPTSTR)GlobalLock(hglb); - if(lptstr) { - text = stdext::utf8_to_latin1(lptstr); + LPWSTR lpwstr = (LPWSTR)GlobalLock(hglb); + if(lpwstr) { + text = stdext::utf16_to_latin1(lpwstr); GlobalUnlock(hglb); } } @@ -954,16 +949,16 @@ std::string WIN32Window::getClipboardText() return text; } + std::string WIN32Window::getPlatformType() { -#ifdef OPENGL_ES +#ifndef OPENGL_ES return "WIN32-WGL"; #else return "WIN32-EGL"; #endif } - Rect WIN32Window::getClientRect() { if(m_window) { diff --git a/src/framework/platform/win32window.h b/src/framework/platform/win32window.h index 77bae995..50f72df5 100644 --- a/src/framework/platform/win32window.h +++ b/src/framework/platform/win32window.h @@ -71,7 +71,7 @@ public: void setMinimumSize(const Size& minimumSize); void setFullscreen(bool fullscreen); void setVerticalSync(bool enable); - void setIcon(const std::string& iconFile); + void setIcon(const std::string& file); void setClipboardText(const std::string& text); Size getDisplaySize(); diff --git a/src/framework/platform/x11window.cpp b/src/framework/platform/x11window.cpp index bb4be4ef..3d20f33d 100644 --- a/src/framework/platform/x11window.cpp +++ b/src/framework/platform/x11window.cpp @@ -20,11 +20,12 @@ * THE SOFTWARE. */ -#if defined __linux || defined __APPLE__ +#ifdef __linux #include "x11window.h" #include -#include +#include +#include #define LSB_BIT_SET(p, n) (p[(n)/8] |= (1 <<((n)%8))) @@ -320,13 +321,6 @@ void X11Window::internalCreateWindow() bool X11Window::internalSetupWindowInput() { - // try to set a latin1 locales, otherwise fallback to standard C locale - static char locales[4][32] = { "en_US.iso88591", "iso88591", "en_US", "C" }; - for(int i=0;i<4;++i) { - if(setlocale(LC_ALL, locales[i])) - break; - } - // create input context (to have better key input handling) if(!XSupportsLocale()) { g_logger.error("X11 doesn't support the current locale"); @@ -515,8 +509,10 @@ bool X11Window::isExtensionSupported(const char *ext) void X11Window::move(const Point& pos) { m_position = pos; - if(m_visible) + if(m_visible) { XMoveWindow(m_display, m_window, m_position.x, m_position.y); + XFlush(m_display); + } } void X11Window::resize(const Size& size) @@ -524,6 +520,7 @@ void X11Window::resize(const Size& size) if(size.width() < m_minimumSize.width() || size.height() < m_minimumSize.height()) return; XResizeWindow(m_display, m_window, size.width(), size.height()); + XFlush(m_display); } void X11Window::show() @@ -678,6 +675,7 @@ void X11Window::poll() Atom typeList[] = { XInternAtom(m_display, "UTF8_STRING", False), XInternAtom(m_display, "TEXT", False), XInternAtom(m_display, "STRING", False), + XInternAtom(m_display, "text/plain;charset=UTF-8", False), XInternAtom(m_display, "text/plain", False), XInternAtom(m_display, "COMPOUND_TEXT", False), XA_STRING }; @@ -689,13 +687,14 @@ void X11Window::poll() sizeof(typeList)); respond.xselection.property = req->property; } else { + std::string clipboardText = stdext::latin1_to_utf8(m_clipboardText); XChangeProperty(m_display, req->requestor, req->property, req->target, 8, PropModeReplace, - (uchar *)m_clipboardText.c_str(), - m_clipboardText.length()); + (uchar *)clipboardText.c_str(), + clipboardText.length()); respond.xselection.property = req->property; } @@ -766,14 +765,16 @@ void X11Window::poll() m_inputEvent.type = Fw::MouseWheelInputEvent; m_inputEvent.mouseButton = Fw::MouseMidButton; m_inputEvent.wheelDirection = Fw::MouseWheelUp; - } + } else + m_inputEvent.type = Fw::NoInputEvent; break; case Button5: if(event.type == ButtonPress) { m_inputEvent.type = Fw::MouseWheelInputEvent; m_inputEvent.mouseButton = Fw::MouseMidButton; m_inputEvent.wheelDirection = Fw::MouseWheelDown; - } + } else + m_inputEvent.type = Fw::NoInputEvent; break; default: m_inputEvent.type = Fw::NoInputEvent; @@ -862,32 +863,28 @@ void X11Window::restoreMouseCursor() void X11Window::setMouseCursor(const std::string& file, const Point& hotSpot) { - std::stringstream fin; - g_resources.loadFile(file, fin); + ImagePtr image = Image::load(file); - apng_data apng; - if(load_apng(fin, &apng) != 0) { - g_logger.traceError(stdext::format("unable to load png file %s", file)); + if(!image) { + g_logger.traceError(stdext::format("unable to load image file %s", file)); return; } - if(apng.bpp != 4) { - g_logger.error("the cursor png must have 4 channels"); - free_apng(&apng); + if(image->getBpp() != 4) { + g_logger.error("the cursor image must have 4 channels"); return; } - if(apng.width != 32|| apng.height != 32) { - g_logger.error("the cursor png must have 32x32 dimension"); - free_apng(&apng); + if(image->getWidth() != 32 || image->getHeight() != 32) { + g_logger.error("the cursor image must have 32x32 dimension"); return; } if(m_cursor != None) restoreMouseCursor(); - int width = apng.width; - int height = apng.height; + int width = image->getWidth(); + int height = image->getHeight(); int numbits = width * height; int numbytes = (width * height)/8; @@ -903,7 +900,7 @@ void X11Window::setMouseCursor(const std::string& file, const Point& hotSpot) std::vector maskBits(numbytes, 0); for(int i=0;igetPixelData() + i*4); if(rgba == 0xffffffff) { //white, background LSB_BIT_SET(maskBits, i); } else if(rgba == 0xff000000) { //black, foreground @@ -911,7 +908,6 @@ void X11Window::setMouseCursor(const std::string& file, const Point& hotSpot) LSB_BIT_SET(maskBits, i); } //otherwise 0x00000000 => alpha } - free_apng(&apng); Pixmap cp = XCreateBitmapFromData(m_display, m_window, (char*)&mapBits[0], width, height); Pixmap mp = XCreateBitmapFromData(m_display, m_window, (char*)&maskBits[0], width, height); @@ -978,40 +974,35 @@ void X11Window::setVerticalSync(bool enable) #endif } -void X11Window::setIcon(const std::string& iconFile) +void X11Window::setIcon(const std::string& file) { - std::stringstream fin; - g_resources.loadFile(iconFile, fin); + ImagePtr image = Image::load(file); - apng_data apng; - if(load_apng(fin, &apng) != 0) { - g_logger.error("Unable to load window icon"); + if(!image) { + g_logger.traceError(stdext::format("unable to load icon file %s", file)); return; } - if(apng.bpp != 4) { - g_logger.error("Could not set window icon, icon image must have 4 channels"); - free_apng(&apng); + if(image->getBpp() != 4) { + g_logger.error("the app icon must have 4 channels"); return; } - int n = apng.width * apng.height; + int n = image->getWidth() * image->getHeight(); std::vector iconData(n + 2); - iconData[0] = apng.width; - iconData[1] = apng.height; + iconData[0] = image->getWidth(); + iconData[1] = image->getHeight(); for(int i=0; i < n;++i) { uint8 *pixel = (uint8*)&iconData[2 + i]; - pixel[2] = *(apng.pdata + (i * 4) + 0); - pixel[1] = *(apng.pdata + (i * 4) + 1); - pixel[0] = *(apng.pdata + (i * 4) + 2); - pixel[3] = *(apng.pdata + (i * 4) + 3); + pixel[2] = *(image->getPixelData() + (i * 4) + 0); + pixel[1] = *(image->getPixelData() + (i * 4) + 1); + pixel[0] = *(image->getPixelData() + (i * 4) + 2); + pixel[3] = *(image->getPixelData() + (i * 4) + 3); } Atom property = XInternAtom(m_display, "_NET_WM_ICON", 0); if(!XChangeProperty(m_display, m_window, property, XA_CARDINAL, 32, PropModeReplace, (const unsigned char*)&iconData[0], iconData.size())) g_logger.error("Couldn't set app icon"); - - free_apng(&apng); } void X11Window::setClipboardText(const std::string& text) @@ -1047,16 +1038,19 @@ std::string X11Window::getClipboardText() Atom type; int format; ulong len, bytesLeft; - uchar *data; + char *data; XGetWindowProperty(m_display, ownerWindow, XA_PRIMARY, 0, 10000000L, 0, XA_STRING, &type, &format, &len, &bytesLeft, - &data); + (uchar**)&data); if(len > 0) { - clipboardText = stdext::utf8_to_latin1((char*)data); + if(stdext::is_valid_utf8(data)) + clipboardText = stdext::utf8_to_latin1(data); + else + clipboardText = data; } } diff --git a/src/framework/platform/x11window.h b/src/framework/platform/x11window.h index becde3c2..82d91846 100644 --- a/src/framework/platform/x11window.h +++ b/src/framework/platform/x11window.h @@ -72,15 +72,13 @@ public: void setMinimumSize(const Size& minimumSize); void setFullscreen(bool fullscreen); void setVerticalSync(bool enable); - void setIcon(const std::string& iconFile); + void setIcon(const std::string& file); void setClipboardText(const std::string& text); Size getDisplaySize(); std::string getClipboardText(); std::string getPlatformType(); - bool isMaximized(); - private: Display *m_display; XVisualInfo *m_visual; diff --git a/src/framework/stdext/string.cpp b/src/framework/stdext/string.cpp index 086c4175..d863ae95 100644 --- a/src/framework/stdext/string.cpp +++ b/src/framework/stdext/string.cpp @@ -24,6 +24,8 @@ #include "format.h" #include #include +#include +#include namespace stdext { @@ -67,36 +69,44 @@ uint64_t hex_to_dec(const std::string& str) return num; } +bool is_valid_utf8(const std::string& src) +{ + try { + boost::locale::conv::from_utf(src, "ISO-8859-1", boost::locale::conv::stop); + return true; + } catch(...) { + return false; + } +} + std::string utf8_to_latin1(const std::string& src) { - auto utf8CharToLatin1 = [](const uchar *utf8, int *read) -> char { - char c = '?'; - uchar opt1 = utf8[0]; - *read = 1; - if(opt1 == 0xc3) { - *read = 2; - uchar opt2 = utf8[1]; - c = 64 + opt2; - } else if(opt1 == 0xc2) { - *read = 2; - uchar opt2 = utf8[1]; - if(opt2 > 0xa1 && opt2 < 0xbb) - c = opt2; - } else if(opt1 < 0xc2) { - c = opt1; - } - return c; - }; + return boost::locale::conv::from_utf(src, "ISO-8859-1"); +} - std::string out; - int len = src.length(); - for(int i=0; i(src); +} + +std::string utf16_to_utf8(const std::wstring& src) +{ + return boost::locale::conv::utf_to_utf(src); +} + +std::string utf16_to_latin1(const std::wstring& src) +{ + return boost::locale::conv::from_utf(src, "ISO-8859-1"); +} + +std::string latin1_to_utf8(const std::string& src) +{ + return boost::locale::conv::to_utf(src, "ISO-8859-1"); +} + +std::wstring latin1_to_utf16(const std::string& src) +{ + return boost::locale::conv::to_utf(src, "ISO-8859-1"); } void tolower(std::string& str) diff --git a/src/framework/stdext/string.h b/src/framework/stdext/string.h index 995f25b3..e5afb312 100644 --- a/src/framework/stdext/string.h +++ b/src/framework/stdext/string.h @@ -42,7 +42,6 @@ std::string date_time_string(); std::string dec_to_hex(uint64_t num); uint64_t hex_to_dec(const std::string& str); -std::string utf8_to_latin1(const std::string& src); void tolower(std::string& str); void toupper(std::string& str); void trim(std::string& str); @@ -53,6 +52,14 @@ bool ends_with(const std::string& str, const std::string& test); bool starts_with(const std::string& str, const std::string& test); void replace_all(std::string& str, const std::string& search, const std::string& replacement); +bool is_valid_utf8(const std::string& src); +std::string utf8_to_latin1(const std::string& src); +std::wstring utf8_to_utf16(const std::string& src); +std::string utf16_to_utf8(const std::wstring& src); +std::string utf16_to_latin1(const std::wstring& src); +std::string latin1_to_utf8(const std::string& src); +std::wstring latin1_to_utf16(const std::string& src); + std::vector split(const std::string& str, const std::string& separators = " "); template std::vector split(const std::string& str, const std::string& separators = " ") { std::vector splitted = split(str, separators);