mirror of
https://github.com/gnif/LookingGlass.git
synced 2026-11-13 15:27:21 +00:00
[common] windows: add native path and UTF support
This commit is contained in:
@@ -14,6 +14,19 @@ set_tests_properties(common-platform-tests PROPERTIES
|
|||||||
TIMEOUT 10
|
TIMEOUT 10
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if(LG_CLIENT_PLATFORM_WINDOWS)
|
||||||
|
add_executable(common-windows-tests
|
||||||
|
common_windows_test.c
|
||||||
|
)
|
||||||
|
target_link_libraries(common-windows-tests
|
||||||
|
${EXE_FLAGS}
|
||||||
|
lg_common
|
||||||
|
)
|
||||||
|
add_test(NAME common-windows-tests
|
||||||
|
COMMAND common-windows-tests
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
add_executable(font-tests
|
add_executable(font-tests
|
||||||
font_test.c
|
font_test.c
|
||||||
../src/font.c
|
../src/font.c
|
||||||
|
|||||||
50
client/tests/common_windows_test.c
Normal file
50
client/tests/common_windows_test.c
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/**
|
||||||
|
* Looking Glass
|
||||||
|
* Copyright © 2017-2026 The Looking Glass Authors
|
||||||
|
* https://looking-glass.io
|
||||||
|
*
|
||||||
|
* 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., 59
|
||||||
|
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "test.h"
|
||||||
|
|
||||||
|
#include "common/win32.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
|
||||||
|
static void testUtfConversion(void)
|
||||||
|
{
|
||||||
|
static const char input[] = "Looking Glass \xF0\x9F\x96\xA5";
|
||||||
|
|
||||||
|
wchar_t * wide = lgUtf8ToWide(input);
|
||||||
|
CHECK(wide);
|
||||||
|
CHECK(wcslen(wide) > 0);
|
||||||
|
|
||||||
|
char * output = lgWideToUtf8(wide);
|
||||||
|
CHECK(output);
|
||||||
|
CHECK(strcmp(output, input) == 0);
|
||||||
|
free(output);
|
||||||
|
free(wide);
|
||||||
|
|
||||||
|
CHECK(!lgUtf8ToWide("\xC0\xAF"));
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
testUtfConversion();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
29
common/include/common/win32.h
Normal file
29
common/include/common/win32.h
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/**
|
||||||
|
* Looking Glass
|
||||||
|
* Copyright © 2017-2026 The Looking Glass Authors
|
||||||
|
* https://looking-glass.io
|
||||||
|
*
|
||||||
|
* 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., 59
|
||||||
|
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _H_LG_COMMON_WIN32_
|
||||||
|
#define _H_LG_COMMON_WIN32_
|
||||||
|
|
||||||
|
#include <wchar.h>
|
||||||
|
|
||||||
|
wchar_t * lgUtf8ToWide(const char * input);
|
||||||
|
char * lgWideToUtf8(const wchar_t * input);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -40,6 +40,9 @@ add_library(lg_common_platform_code STATIC
|
|||||||
windebug.c
|
windebug.c
|
||||||
ivshmem.c
|
ivshmem.c
|
||||||
time.c
|
time.c
|
||||||
|
win32.c
|
||||||
|
paths.c
|
||||||
|
open.c
|
||||||
cpuinfo.c
|
cpuinfo.c
|
||||||
display.c
|
display.c
|
||||||
proctitle.c
|
proctitle.c
|
||||||
@@ -50,6 +53,9 @@ target_link_libraries(lg_common_platform_code
|
|||||||
setupapi
|
setupapi
|
||||||
bcrypt
|
bcrypt
|
||||||
ntdll
|
ntdll
|
||||||
|
ole32
|
||||||
|
shell32
|
||||||
|
uuid
|
||||||
)
|
)
|
||||||
|
|
||||||
if (ENABLE_BACKTRACE)
|
if (ENABLE_BACKTRACE)
|
||||||
|
|||||||
@@ -23,11 +23,12 @@
|
|||||||
|
|
||||||
bool display_getPathInfo(HMONITOR monitor, DISPLAYCONFIG_PATH_INFO * info)
|
bool display_getPathInfo(HMONITOR monitor, DISPLAYCONFIG_PATH_INFO * info)
|
||||||
{
|
{
|
||||||
bool result = false;
|
bool result = false;
|
||||||
UINT32 numPath, numMode;
|
UINT32 numPath;
|
||||||
|
UINT32 numMode;
|
||||||
|
|
||||||
MONITORINFOEXW viewInfo = { .cbSize = sizeof(viewInfo) };
|
MONITORINFOEXW viewInfo = { .cbSize = sizeof(viewInfo) };
|
||||||
if (!GetMonitorInfoW(monitor, (MONITORINFO*)&viewInfo))
|
if (!GetMonitorInfoW(monitor, (MONITORINFO*)&viewInfo))
|
||||||
{
|
{
|
||||||
DEBUG_ERROR("Failed to get the monitor info");
|
DEBUG_ERROR("Failed to get the monitor info");
|
||||||
goto err;
|
goto err;
|
||||||
@@ -37,11 +38,11 @@ err_retry:
|
|||||||
if (FAILED(GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &numPath, &numMode)))
|
if (FAILED(GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, &numPath, &numMode)))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
DISPLAYCONFIG_PATH_INFO * pathInfo = calloc(sizeof(*pathInfo), numPath);
|
DISPLAYCONFIG_PATH_INFO * pathInfo = calloc(numPath, sizeof(*pathInfo));
|
||||||
if (!pathInfo)
|
if (!pathInfo)
|
||||||
goto err_mem_pathInfo;
|
goto err_mem_pathInfo;
|
||||||
|
|
||||||
DISPLAYCONFIG_MODE_INFO * modeInfo = calloc(sizeof(*modeInfo), numMode);
|
DISPLAYCONFIG_MODE_INFO * modeInfo = calloc(numMode, sizeof(*modeInfo));
|
||||||
if (!modeInfo)
|
if (!modeInfo)
|
||||||
goto err_mem_modeInfo;
|
goto err_mem_modeInfo;
|
||||||
|
|
||||||
|
|||||||
45
common/src/platform/windows/open.c
Normal file
45
common/src/platform/windows/open.c
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
/**
|
||||||
|
* Looking Glass
|
||||||
|
* Copyright © 2017-2026 The Looking Glass Authors
|
||||||
|
* https://looking-glass.io
|
||||||
|
*
|
||||||
|
* 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., 59
|
||||||
|
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "common/open.h"
|
||||||
|
|
||||||
|
#include "common/debug.h"
|
||||||
|
#include "common/win32.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
bool lgOpenURL(const char * url)
|
||||||
|
{
|
||||||
|
wchar_t * wideUrl = lgUtf8ToWide(url);
|
||||||
|
if (!wideUrl)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const INT_PTR result = (INT_PTR)ShellExecuteW(
|
||||||
|
NULL, L"open", wideUrl, NULL, NULL, SW_SHOWNORMAL);
|
||||||
|
free(wideUrl);
|
||||||
|
if (result > 32)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
DEBUG_ERROR("Failed to open URL (ShellExecute result: %lld)",
|
||||||
|
(long long)result);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
116
common/src/platform/windows/paths.c
Normal file
116
common/src/platform/windows/paths.c
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
/**
|
||||||
|
* Looking Glass
|
||||||
|
* Copyright © 2017-2026 The Looking Glass Authors
|
||||||
|
* https://looking-glass.io
|
||||||
|
*
|
||||||
|
* 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., 59
|
||||||
|
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "common/paths.h"
|
||||||
|
|
||||||
|
#include "common/debug.h"
|
||||||
|
#include "common/windebug.h"
|
||||||
|
#include "common/win32.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <windows.h>
|
||||||
|
#include <knownfolders.h>
|
||||||
|
#include <shlobj.h>
|
||||||
|
|
||||||
|
static char * configDir;
|
||||||
|
static char * dataDir;
|
||||||
|
|
||||||
|
static char * makePath(
|
||||||
|
REFKNOWNFOLDERID folderId, const wchar_t * appName)
|
||||||
|
{
|
||||||
|
PWSTR base;
|
||||||
|
const HRESULT status = SHGetKnownFolderPath(folderId, 0, NULL, &base);
|
||||||
|
if (FAILED(status))
|
||||||
|
{
|
||||||
|
DEBUG_WINERROR("Failed to locate application data directory", status);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t baseLength = wcslen(base);
|
||||||
|
const size_t appLength = wcslen(appName);
|
||||||
|
if (baseLength > SIZE_MAX - appLength - 2)
|
||||||
|
{
|
||||||
|
CoTaskMemFree(base);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
wchar_t * path = malloc(
|
||||||
|
(baseLength + appLength + 2) * sizeof(*path));
|
||||||
|
if (!path)
|
||||||
|
{
|
||||||
|
CoTaskMemFree(base);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(path, base, baseLength * sizeof(*path));
|
||||||
|
path[baseLength] = L'\\';
|
||||||
|
memcpy(path + baseLength + 1, appName,
|
||||||
|
(appLength + 1) * sizeof(*path));
|
||||||
|
CoTaskMemFree(base);
|
||||||
|
|
||||||
|
if (!CreateDirectoryW(path, NULL) && GetLastError() != ERROR_ALREADY_EXISTS)
|
||||||
|
{
|
||||||
|
DEBUG_WINERROR("Failed to create application data directory",
|
||||||
|
GetLastError());
|
||||||
|
free(path);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char * result = lgWideToUtf8(path);
|
||||||
|
free(path);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void lgPathsInit(const char * appName)
|
||||||
|
{
|
||||||
|
wchar_t * wideName = lgUtf8ToWide(appName);
|
||||||
|
if (!wideName)
|
||||||
|
{
|
||||||
|
DEBUG_ERROR("Invalid UTF-8 application name");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char * newConfigDir = makePath(&FOLDERID_RoamingAppData, wideName);
|
||||||
|
char * newDataDir = makePath(&FOLDERID_LocalAppData, wideName);
|
||||||
|
free(wideName);
|
||||||
|
if (!newConfigDir || !newDataDir)
|
||||||
|
{
|
||||||
|
free(newConfigDir);
|
||||||
|
free(newDataDir);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(configDir);
|
||||||
|
free(dataDir);
|
||||||
|
configDir = newConfigDir;
|
||||||
|
dataDir = newDataDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char * lgConfigDir(void)
|
||||||
|
{
|
||||||
|
return configDir ? configDir : ".";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char * lgDataDir(void)
|
||||||
|
{
|
||||||
|
return dataDir ? dataDir : ".";
|
||||||
|
}
|
||||||
@@ -22,6 +22,9 @@
|
|||||||
|
|
||||||
void lgInitProcessTitle(int argc, char **pargv[])
|
void lgInitProcessTitle(int argc, char **pargv[])
|
||||||
{
|
{
|
||||||
|
(void)argc;
|
||||||
|
(void)pargv;
|
||||||
|
|
||||||
// not implemented on Windows
|
// not implemented on Windows
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,5 +35,7 @@ bool lgCanSetProcessTitle(void)
|
|||||||
|
|
||||||
void lgSetProcessTitle(const char * title)
|
void lgSetProcessTitle(const char * title)
|
||||||
{
|
{
|
||||||
|
(void)title;
|
||||||
|
|
||||||
// not implemented on Windows
|
// not implemented on Windows
|
||||||
}
|
}
|
||||||
|
|||||||
72
common/src/platform/windows/win32.c
Normal file
72
common/src/platform/windows/win32.c
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
/**
|
||||||
|
* Looking Glass
|
||||||
|
* Copyright © 2017-2026 The Looking Glass Authors
|
||||||
|
* https://looking-glass.io
|
||||||
|
*
|
||||||
|
* 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., 59
|
||||||
|
* Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "common/win32.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
wchar_t * lgUtf8ToWide(const char * input)
|
||||||
|
{
|
||||||
|
if (!input)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
const int length = MultiByteToWideChar(
|
||||||
|
CP_UTF8, MB_ERR_INVALID_CHARS, input, -1, NULL, 0);
|
||||||
|
if (!length)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
wchar_t * output = malloc((size_t)length * sizeof(*output));
|
||||||
|
if (!output)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!MultiByteToWideChar(
|
||||||
|
CP_UTF8, MB_ERR_INVALID_CHARS, input, -1, output, length))
|
||||||
|
{
|
||||||
|
free(output);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
char * lgWideToUtf8(const wchar_t * input)
|
||||||
|
{
|
||||||
|
if (!input)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
const int length = WideCharToMultiByte(
|
||||||
|
CP_UTF8, WC_ERR_INVALID_CHARS, input, -1, NULL, 0, NULL, NULL);
|
||||||
|
if (!length)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
char * output = malloc((size_t)length);
|
||||||
|
if (!output)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS,
|
||||||
|
input, -1, output, length, NULL, NULL))
|
||||||
|
{
|
||||||
|
free(output);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user