mirror of
https://github.com/edubart/otclient.git
synced 2025-10-20 06:23:26 +02:00
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
This commit is contained in:
@@ -23,9 +23,8 @@
|
||||
#ifdef WIN32
|
||||
|
||||
#include "win32window.h"
|
||||
|
||||
#include <framework/graphics/image.h>
|
||||
#include <framework/core/application.h>
|
||||
#include <framework/graphics/apngloader.h>
|
||||
#include <framework/core/resourcemanager.h>
|
||||
|
||||
#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<uchar> xorMask(numbytes, 0);
|
||||
|
||||
for(int i=0;i<numbits;++i) {
|
||||
uint32 rgba = stdext::readLE32(apng.pdata + i*4);
|
||||
uint32 rgba = stdext::readLE32(image->getPixelData() + 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<uint32> 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<uint32> 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) {
|
||||
|
@@ -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();
|
||||
|
@@ -20,11 +20,12 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#if defined __linux || defined __APPLE__
|
||||
#ifdef __linux
|
||||
|
||||
#include "x11window.h"
|
||||
#include <framework/core/resourcemanager.h>
|
||||
#include <framework/graphics/apngloader.h>
|
||||
#include <framework/graphics/image.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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<uchar> maskBits(numbytes, 0);
|
||||
|
||||
for(int i=0;i<numbits;++i) {
|
||||
uint32 rgba = stdext::readLE32(apng.pdata + i*4);
|
||||
uint32 rgba = stdext::readLE32(image->getPixelData() + 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<unsigned long int> 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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;
|
||||
|
Reference in New Issue
Block a user