unicode support in win32 layer

This commit is contained in:
jacob 2024-04-03 19:34:52 -05:00
parent db16c4b067
commit 9a8b712f98
10 changed files with 312 additions and 262 deletions

View File

@ -514,15 +514,6 @@ INLINE i64 clamp_i64(i64 v, i64 min, i64 max) { return v < min ? min : v > max ?
INLINE f32 clamp_f32(f32 v, f32 min, f32 max) { return v < min ? min : v > max ? max : v; }
INLINE f64 clamp_f64(f64 v, f64 min, f64 max) { return v < min ? min : v > max ? max : v; }
INLINE u64 cstr_len(char *cstr)
{
u64 len = 0;
for (char *c = cstr; *c != 0; ++c) {
++len;
}
return len;
}
/* ========================== *
* Profiling
* ========================== */

View File

@ -186,7 +186,7 @@ struct asset *font_load_asset(struct string path, f32 point_size, b32 help)
STR("Font path \"%F\" too long!"),
FMT_STR(path)));
}
string_to_cstr_buff(path, BUFFER_FROM_ARRAY(params->path_cstr));
cstr_buff_from_string(BUFFER_FROM_ARRAY(params->path_cstr), path);
params->path_len = path.len;
params->asset = asset;
params->point_size = point_size;

View File

@ -8,6 +8,7 @@
struct resource {
struct buffer bytes;
/* Internal */
#if !RESOURCES_EMBEDDED
struct sys_file file;
struct sys_file_map file_map;

View File

@ -236,7 +236,7 @@ struct asset *sheet_load_asset(struct string path, b32 help)
STR("Sheet path \"%F\" too long!"),
FMT_STR(path)));
}
string_to_cstr_buff(path, BUFFER_FROM_ARRAY(params->path_cstr));
cstr_buff_from_string(BUFFER_FROM_ARRAY(params->path_cstr), path);
params->path_len = path.len;
params->asset = asset;

View File

@ -191,7 +191,7 @@ struct asset *sound_load_asset(struct string path, u32 flags, b32 help)
STR("Sound path \"%F\" too long!"),
FMT_STR(path)));
}
string_to_cstr_buff(path, BUFFER_FROM_ARRAY(params->path_cstr));
cstr_buff_from_string(BUFFER_FROM_ARRAY(params->path_cstr), path);
params->path_len = path.len;
params->asset = asset;
params->flags = flags;

View File

@ -160,54 +160,17 @@ struct string string_copy(struct arena *arena, struct string src)
return str;
}
struct string string_copy_buff(struct buffer buff, struct string src)
struct string string_copy_buff(struct buffer dest_buff, struct string src)
{
u64 len = min_u64(buff.size, src.len);
u64 len = min_u64(dest_buff.size, src.len);
struct string str = {
.len = len,
.text = buff.data
.text = dest_buff.data
};
MEMCPY(str.text, src.text, src.len);
return str;
}
/* TODO: Benchmark performance of appending each character while calculating size here */
// //struct string string_copy_cstr(struct arena *arena, char *cstr)
// //{
// // u8 *final_text = arena_next(arena);
// // char *c = cstr;
// // for (; *c != 0; ++c) {
// // u8 *new_char = arena_push(arena, 1);
// // *new_char = *c;
// // }
// // return (struct string) {
// // .len = c - cstr,
// // .text = final_text
// // };
// //}
struct string string_from_cstr(char *cstr)
{
struct string str = { 0 };
if (cstr) {
char *c = cstr;
while (*c != 0) {
++c;
}
str.len = c - cstr;
str.text = (u8 *)cstr;
}
return str;
}
struct string string_from_cstr_len(char *cstr, u64 len)
{
return (struct string) {
.text = (u8 *)cstr,
.len = len
};
}
struct string string_repeat(struct arena *arena, struct string src, u64 count)
{
u64 final_len = src.len * count;
@ -365,54 +328,6 @@ b32 string_ends_with(struct string str, struct string substring)
return false;
}
#if 0
/* NOTE: This is a LOSSY conversion.
* `wstr` must be null-terminated.
*/
struct string string_from_wstr(struct arena *arena, u16 *wstr)
{
u8 *final_text = arena_next(arena);
u16 *wchar = wstr;
for (; *wchar != 0; ++wchar) {
u8 *c = arena_push(arena, 1);
*c = (u8)(*wchar & 0xFF);
}
return (struct string) {
.len = wchar - wstr,
.text = final_text
};
}
#endif
char *string_to_cstr(struct arena *arena, struct string str)
{
u8 *text = arena_push_array(arena, u8, str.len + 1);
MEMCPY(text, str.text, str.len);
text[str.len] = '\0';
return (char *)text;
}
char *string_to_cstr_buff(struct string str, struct buffer buff)
{
if (buff.size > 0) {
u64 len = min_u64(str.len, buff.size - 1);
MEMCPY(buff.data, str.text, len);
buff.data[len] = '\0';
}
return (char *)buff.data;
}
wchar_t *string_to_wstr(struct arena *arena, struct string str)
{
/* FIXME: Do proper encoding. */
u16 *text = arena_push_array(arena, u16, str.len + 1);
for (u64 i = 0; i < str.len; ++i) {
text[i] = (u16)str.text[i];
}
text[str.len] = '\0';
return (wchar_t *)text;
}
/* ========================== *
* Format
* ========================== */
@ -549,7 +464,7 @@ struct string _string_format(struct arena *arena, struct string fmt, ...)
}
/* ========================== *
* Unicode transformation
* Unicode
* ========================== */
/* utf8 <- utf16 */
@ -576,6 +491,30 @@ struct string string_from_string16(struct arena *arena, struct string16 str16)
return res;
}
/* utf8 <- utf32 */
struct string string_from_string32(struct arena *arena, struct string32 str32)
{
struct string res = {
.len = 0,
.text = arena_dry_push(arena, u8)
};
u64 pos32 = 0;
while (pos32 < str32.len) {
struct string32 str32_remaining = { .len = (str32.len - pos32), .text = str32.text + pos32 };
struct utf32_decode_result decoded = utf32_decode(str32_remaining);
struct utf8_encode_result encoded = utf8_encode(decoded.codepoint);
u8 *dest = arena_push_array(arena, u8, encoded.count8);
MEMCPY(dest, &encoded.chars8, encoded.count8);
pos32 += 1;
res.len += encoded.count8;
}
return res;
}
/* utf16 <- utf8 */
struct string16 string16_from_string(struct arena *arena, struct string str8)
{
@ -600,30 +539,6 @@ struct string16 string16_from_string(struct arena *arena, struct string str8)
return res;
}
/* utf8 <- utf32 */
struct string string_from_string32(struct arena *arena, struct string32 str32)
{
struct string res = {
.len = 0,
.text = arena_dry_push(arena, u8)
};
u64 pos32 = 0;
while (pos32 < str32.len) {
struct string32 str32_remaining = { .len = (str32.len - pos32), .text = str32.text + pos32 };
struct utf32_decode_result decoded = utf32_decode(str32_remaining);
struct utf8_encode_result encoded = utf8_encode(decoded.codepoint);
u8 *dest = arena_push_array(arena, u8, encoded.count8);
MEMCPY(dest, &encoded.chars8, encoded.count8);
pos32 += 1;
res.len += encoded.count8;
}
return res;
}
/* utf32 <- utf8 */
struct string32 string32_from_string(struct arena *arena, struct string str8)
{
@ -647,3 +562,93 @@ struct string32 string32_from_string(struct arena *arena, struct string str8)
return res;
}
/* ========================== *
* Legacy strings
* ========================== */
/* C narrow strings */
u64 cstr_len(char *cstr)
{
char *end = cstr;
while (*end) {
++end;
}
return end - cstr;
}
char *cstr_from_string(struct arena *arena, struct string src)
{
u8 *text = arena_push_array(arena, u8, src.len + 1);
MEMCPY(text, src.text, src.len);
text[src.len] = 0;
return (char *)text;
}
char *cstr_buff_from_string(struct buffer dest_buff, struct string src)
{
if (dest_buff.size > 0) {
u64 len = min_u64(src.len, dest_buff.size - 1);
MEMCPY(dest_buff.data, src.text, len);
dest_buff.data[len] = 0;
}
return (char *)dest_buff.data;
}
struct string string_from_cstr(char *cstr)
{
u64 len = cstr_len(cstr);
return (struct string) {
.len = len,
.text = (u8 *)cstr
};
}
struct string string_from_cstr_len(char *cstr, u64 len)
{
return (struct string) {
.text = (u8 *)cstr,
.len = len
};
}
/* C wide strings */
u64 wstr_len(wchar_t *wstr)
{
wchar_t *end = wstr;
while (*end) {
++end;
}
return end - wstr;
}
wchar_t *wstr_from_string(struct arena *arena, struct string src)
{
struct string16 str16 = string16_from_string(arena, src);
*arena_push(arena, u16) = 0;
return (wchar_t *)str16.text;
}
wchar_t *wstr_from_string16(struct arena *arena, struct string16 src)
{
u16 *text = arena_push_array(arena, u16, src.len + 1);
text[src.len] = 0;
return (wchar_t *)text;
}
struct string string_from_wstr(struct arena *arena, wchar_t *wstr)
{
struct string16 str16 = string16_from_wstr(wstr);
return string_from_string16(arena, str16);
}
struct string16 string16_from_wstr(wchar_t *wstr)
{
u64 len = wstr_len(wstr);
return (struct string16) {
.len = len,
.text = (u16 *)wstr
};
}

View File

@ -21,9 +21,7 @@ struct string string_from_float(struct arena *arena, f64 f, u32 precision);
* ========================== */
struct string string_copy(struct arena *arena, struct string src);
struct string string_copy_buff(struct buffer buff, struct string src);
struct string string_from_cstr(char *cstr);
struct string string_from_cstr_len(char *cstr, u64 len);
struct string string_copy_buff(struct buffer dest_buff, struct string src);
struct string string_repeat(struct arena *arena, struct string src, u64 count);
struct string string_cat(struct arena *arena, struct string str1, struct string str2);
struct string_array string_split(struct arena *arena, struct string str, struct string delim);
@ -32,9 +30,6 @@ b32 string_eq(struct string str1, struct string str2);
b32 string_contains(struct string str, struct string substring);
b32 string_starts_with(struct string str, struct string substring);
b32 string_ends_with(struct string str, struct string substring);
char *string_to_cstr(struct arena *arena, struct string str);
char *string_to_cstr_buff(struct string str, struct buffer buff);
wchar_t *string_to_wstr(struct arena *arena, struct string str);
/* ========================== *
* Format
@ -86,12 +81,28 @@ struct string _string_format(struct arena *arena, struct string fmt, ...);
struct string string_formatv(struct arena *arena, struct string fmt, va_list args);
/* ========================== *
* Unicode transformation
* Unicode
* ========================== */
struct string string_from_string16(struct arena *arena, struct string16 str16);
struct string16 string16_from_string(struct arena *arena, struct string str8);
struct string string_from_string32(struct arena *arena, struct string32 str32);
struct string16 string16_from_string(struct arena *arena, struct string str8);
struct string32 string32_from_string(struct arena *arena, struct string str8);
/* ========================== *
* Legacy strings
* ========================== */
u64 cstr_len(char *cstr);
char *cstr_from_string(struct arena *arena, struct string src);
char *cstr_buff_from_string(struct buffer dest_buff, struct string src);
struct string string_from_cstr(char *cstr);
struct string string_from_cstr_len(char *cstr, u64 len);
u64 wstr_len(wchar_t *wstr);
wchar_t *wstr_from_string(struct arena *arena, struct string src);
wchar_t *wstr_from_string16(struct arena *arena, struct string16 src);
struct string string_from_wstr(struct arena *arena, wchar_t *wstr);
struct string16 string16_from_wstr(wchar_t *wstr);
#endif

View File

@ -195,8 +195,8 @@ u64 sys_file_size(struct sys_file file);
* ========================== */
struct sys_file_map {
u64 handle;
struct buffer mapped_memory;
u64 handle;
};
struct sys_file_map sys_file_map_open_read(struct sys_file file);
@ -207,18 +207,20 @@ struct buffer sys_file_map_data(struct sys_file_map map);
* Dir iter
* ========================== */
/* Opaque */
struct sys_dir_iter;
struct sys_dir_iter_info {
struct string file_name;
struct sys_file_filter_result {
struct string filename;
b32 is_dir;
};
struct sys_file_filter {
struct sys_file_filter_result info;
u64 handle;
};
/* Iterate all files in a directory */
struct sys_dir_iter *sys_dir_iter_begin(struct arena *arena, struct string dir_name);
struct sys_dir_iter_info *sys_dir_iter_next(struct arena *arena, struct sys_dir_iter *iter);
void sys_dir_iter_end(struct sys_dir_iter *iter);
struct sys_file_filter sys_file_filter_begin(struct arena *arena, struct string pattern);
b32 sys_file_filter_next(struct arena *arena, struct sys_file_filter *iter);
void sys_file_filter_end(struct sys_file_filter *iter);
/* ========================== *
* Window

View File

@ -10,6 +10,7 @@
#include "math.h"
#include "util.h"
#include "tls.h"
#include "utf.h"
#include <Windows.h>
#include <windowsx.h>
@ -27,6 +28,7 @@
#pragma comment(lib, "dwmapi")
#define SYS_WINDOW_EVENT_LISTENERS_MAX 512
#define WINDOW_CLASS_NAME L"power_play_window_class"
struct win32_thread_params {
sys_thread_func *thread_func;
@ -107,7 +109,7 @@ GLOBAL struct {
struct win32_thread_params *first_free_thread_params;
/* Windows */
WNDCLASSEX window_class;
WNDCLASSEXW window_class;
struct sys_mutex windows_mutex;
struct arena windows_arena;
struct win32_window *first_free_window;
@ -187,39 +189,39 @@ void sys_memory_decommit(void *address, u64 size)
VirtualFree(address, size, MEM_DECOMMIT);
}
/* ========================== *
* Wchar
*
* TODO: Move wide char ops to string.c and actually do proper decoding
* ========================== */
INTERNAL struct string wchar_path_to_string(struct arena *arena, wchar_t *src)
{
struct string str = { 0, arena_dry_push(arena, u8) };
while (1) {
wchar_t wchar = src[str.len];
if (wchar != 0) {
if (wchar == '\\') {
wchar = '/';
}
u8 *c = arena_push(arena, u8);
/* FIXME: We're ignoring the high byte here */
*c = (u8)(wchar & 0xFF);
++str.len;
} else {
break;
}
}
return str;
}
/* ========================== *
* File system
* ========================== */
INTERNAL struct string string_from_win32_path(struct arena *arena, wchar_t *src)
{
struct string res = {
.len = 0,
.text = arena_dry_push(arena, u8)
};
while (*src) {
struct string16 decode_str = { .len = *(src + 1) ? 2 : 1, .text = src };
struct utf16_decode_result decoded = utf16_decode(decode_str);
struct utf8_encode_result encoded = utf8_encode(decoded.codepoint);
u8 *dest = arena_push_array(arena, u8, encoded.count8);
for (u32 i = 0; i < encoded.count8; ++i) {
u8 byte = encoded.chars8[i];
if (byte == '\\') {
byte = '/';
}
dest[i] = byte;
}
res.len += encoded.count8;
src += decoded.advance16;
}
return res;
}
struct string sys_get_write_path(struct arena *arena)
{
wchar_t *p = NULL;
u16 *p = NULL;
/* TODO: cache this? */
HRESULT res = SHGetKnownFolderPath(
&FOLDERID_LocalAppData,
@ -229,7 +231,7 @@ struct string sys_get_write_path(struct arena *arena)
);
struct string path = { 0 };
if (res == S_OK) {
path = wchar_path_to_string(arena, p);
path = string_from_win32_path(arena, p);
}
CoTaskMemFree(p);
return path;
@ -239,8 +241,8 @@ b32 sys_is_file(struct string path)
{
__prof;
struct temp_arena scratch = scratch_begin_no_conflict();
const char *path_cstr = string_to_cstr(scratch.arena, path);
DWORD attributes = GetFileAttributes(path_cstr);
wchar_t *path_wstr = wstr_from_string(scratch.arena, path);
DWORD attributes = GetFileAttributesW(path_wstr);
scratch_end(scratch);
return attributes != INVALID_FILE_ATTRIBUTES && !(attributes & FILE_ATTRIBUTE_DIRECTORY);
}
@ -248,8 +250,8 @@ b32 sys_is_file(struct string path)
b32 sys_is_dir(struct string path)
{
struct temp_arena scratch = scratch_begin_no_conflict();
const char *path_cstr = string_to_cstr(scratch.arena, path);
DWORD attributes = GetFileAttributes(path_cstr);
wchar_t *path_wstr = wstr_from_string(scratch.arena, path);
DWORD attributes = GetFileAttributesW(path_wstr);
scratch_end(scratch);
return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY);
}
@ -258,10 +260,35 @@ void sys_mkdir(struct string path)
{
__prof;
struct temp_arena scratch = scratch_begin_no_conflict();
const char *path_cstr = string_to_cstr(scratch.arena, path);
b32 success = SHCreateDirectoryExA(NULL, path_cstr, NULL) == ERROR_SUCCESS;
(UNUSED)success;
ASSERT(success);
wchar_t *path_wstr = wstr_from_string(scratch.arena, path);
int err_code = SHCreateDirectory(NULL, path_wstr);
struct string err = { 0 };
switch (err_code) {
case ERROR_BAD_PATHNAME: {
err = STR("Bad path name");
} break;
case ERROR_FILENAME_EXCED_RANGE: {
err = STR("Path name too long");
} break;
case ERROR_FILE_EXISTS: {
err = STR("A file already exists at this location");
} break;
case ERROR_CANCELLED: {
err = STR("User canceled the operation");
} break;
default: break;
}
if (err.len > 0) {
struct string msg = string_format(scratch.arena,
STR("Failed to create directory \"%F\": %F"),
FMT_STR(path),
FMT_STR(err));
sys_panic(msg);
}
scratch_end(scratch);
}
@ -269,11 +296,11 @@ struct sys_file sys_file_open_read(struct string path)
{
__prof;
struct temp_arena scratch = scratch_begin_no_conflict();
const char *path_cstr = string_to_cstr(scratch.arena, path);
wchar_t *path_wstr = wstr_from_string(scratch.arena, path);
/* TODO: Handle errors / non-existing file (handle == INVALID_HANDLE_VALUE) */
HANDLE handle = CreateFileA(
path_cstr,
HANDLE handle = CreateFileW(
path_wstr,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
@ -290,9 +317,9 @@ struct sys_file sys_file_open_write(struct string path)
{
__prof;
struct temp_arena scratch = scratch_begin_no_conflict();
const char *path_cstr = string_to_cstr(scratch.arena, path);
HANDLE handle = CreateFileA(
path_cstr,
wchar_t *path_wstr = wstr_from_string(scratch.arena, path);
HANDLE handle = CreateFileW(
path_wstr,
GENERIC_WRITE,
0,
NULL,
@ -310,9 +337,9 @@ struct sys_file sys_file_open_append(struct string path)
{
__prof;
struct temp_arena scratch = scratch_begin_no_conflict();
const char *path_cstr = string_to_cstr(scratch.arena, path);
HANDLE handle = CreateFileA(
path_cstr,
wchar_t *path_wstr = wstr_from_string(scratch.arena, path);
HANDLE handle = CreateFileW(
path_wstr,
FILE_APPEND_DATA,
FILE_SHARE_READ,
NULL,
@ -395,7 +422,7 @@ u64 sys_file_size(struct sys_file file)
struct sys_file_map sys_file_map_open_read(struct sys_file file)
{
HANDLE map_handle = CreateFileMappingA(
HANDLE map_handle = CreateFileMappingW(
(HANDLE)file.handle,
NULL,
PAGE_READONLY,
@ -451,60 +478,57 @@ struct buffer sys_file_map_data(struct sys_file_map map)
}
/* ========================== *
* Dir iter
* File iter
* ========================== */
struct sys_dir_iter {
HANDLE handle;
char *dir_path_cstr;
struct win32_file_filter {
HANDLE find_handle;
wchar_t *filter_wstr;
};
struct sys_dir_iter *sys_dir_iter_begin(struct arena *arena, struct string dir_name)
struct sys_file_filter sys_file_filter_begin(struct arena *arena, struct string pattern)
{
struct temp_arena scratch = scratch_begin(arena);
struct sys_dir_iter *iter = arena_push_zero(arena, struct sys_dir_iter);
if (dir_name.len >= 1 && dir_name.text[dir_name.len - 1] == '/') {
struct string dir_path_w_asterisk = string_cat(scratch.arena, dir_name, STR("*"));
iter->dir_path_cstr = string_to_cstr(arena, dir_path_w_asterisk);
} else {
/* Invalid directory path supplied */
ASSERT(false);
}
scratch_end(scratch);
return iter;
struct sys_file_filter filter = { 0 };
struct win32_file_filter *filter_internal = arena_push_zero(arena, struct win32_file_filter);
filter_internal->filter_wstr = wstr_from_string(arena, pattern);
filter.handle = (u64)filter_internal;
return filter;
}
struct sys_dir_iter_info *sys_dir_iter_next(struct arena *arena, struct sys_dir_iter *iter)
b32 sys_file_filter_next(struct arena *arena, struct sys_file_filter *filter)
{
WIN32_FIND_DATA find_file_data = { 0 };
struct win32_file_filter *filter_internal = (struct win32_file_filter *)filter->handle;
WIN32_FIND_DATAW find_file_data = { 0 };
b32 found = false;
if (iter->handle) {
found = FindNextFileA(iter->handle, &find_file_data);
} else if (iter->dir_path_cstr) {
iter->handle = FindFirstFileExA(iter->dir_path_cstr, FindExInfoStandard, &find_file_data, FindExSearchNameMatch, NULL, FIND_FIRST_EX_LARGE_FETCH);
found = iter->handle != INVALID_HANDLE_VALUE;
if (filter_internal->find_handle) {
found = FindNextFileW(filter_internal->find_handle, &find_file_data);
} else {
filter_internal->find_handle = FindFirstFileExW(filter_internal->filter_wstr, FindExInfoStandard, &find_file_data, FindExSearchNameMatch, NULL, FIND_FIRST_EX_CASE_SENSITIVE | FIND_FIRST_EX_LARGE_FETCH);
found = filter_internal->find_handle != INVALID_HANDLE_VALUE;
}
struct sys_dir_iter_info *info = NULL;
if (found) {
struct string file_name = string_from_cstr(find_file_data.cFileName);
struct string file_name = string_from_wstr(arena, find_file_data.cFileName);
if (string_eq(file_name, STR(".")) || string_eq(file_name, STR(".."))) {
/* Skip initial '.' and '..' matches */
info = sys_dir_iter_next(arena, iter);
found = sys_file_filter_next(arena, filter);
} else {
info = arena_push_zero(arena, struct sys_dir_iter_info);
info->is_dir = find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
info->file_name = string_copy(arena, file_name);
filter->info.is_dir = find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
filter->info.filename = string_copy(arena, file_name);
}
}
return info;
return found;
}
void sys_dir_iter_end(struct sys_dir_iter *iter)
void sys_file_filter_end(struct sys_file_filter *filter)
{
FindClose(iter->handle);
struct win32_file_filter *filter_internal = (struct win32_file_filter *)filter->handle;
if (filter_internal->find_handle) {
FindClose(filter_internal->find_handle);
}
}
/* ========================== *
@ -536,10 +560,10 @@ INTERNAL HWND win32_create_window(struct win32_window *window)
DWORD exstyle = WS_EX_APPWINDOW | WS_EX_NOREDIRECTIONBITMAP;
/* TODO: Check for hwnd success */
HWND hwnd = CreateWindowExA(
HWND hwnd = CreateWindowExW(
exstyle,
L.window_class.lpszClassName,
"",
L"",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
@ -556,7 +580,7 @@ INTERNAL HWND win32_create_window(struct win32_window *window)
DwmSetWindowAttribute(hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE, (LPCVOID)&dark_mode, sizeof(dark_mode));
/* Set window as userdata */
SetWindowLongPtrA(hwnd, GWLP_USERDATA, (LONG_PTR)window);
SetWindowLongPtrW(hwnd, GWLP_USERDATA, (LONG_PTR)window);
return hwnd;
}
@ -779,7 +803,7 @@ INTERNAL void win32_update_window_from_settings(struct win32_window *window, str
if (fullscreen) {
if (!old_fullscreen) {
/* Entering fullscreen */
SetWindowLongPtrA(hwnd, GWL_STYLE, WS_POPUP);
SetWindowLongPtrW(hwnd, GWL_STYLE, WS_POPUP);
}
rect = (RECT) {
.left = 0,
@ -790,7 +814,7 @@ INTERNAL void win32_update_window_from_settings(struct win32_window *window, str
} else {
if (old_fullscreen) {
/* Leaving fullscreen */
SetWindowLongPtrA(hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW);
SetWindowLongPtrW(hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW);
}
rect = (RECT) {
.left = settings->floating_x,
@ -808,21 +832,26 @@ INTERNAL void win32_update_window_from_settings(struct win32_window *window, str
};
SetWindowPlacement(hwnd, &wp);
SetWindowTextA(hwnd, settings->title);
{
struct temp_arena scratch = scratch_begin_no_conflict();
wchar_t *title_wstr = wstr_from_string(scratch.arena, string_from_cstr(settings->title));
SetWindowTextW(hwnd, title_wstr);
scratch_end(scratch);
}
}
INTERNAL void win32_window_wake(struct win32_window *window)
{
/* Post a blank message to the window's thread message queue to wake it. */
PostMessageA(window->hwnd, WM_NULL, 0, 0);
PostMessageW(window->hwnd, WM_NULL, 0, 0);
}
INTERNAL LRESULT CALLBACK win32_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
struct win32_window *window = (struct win32_window *)GetWindowLongPtrA(hwnd, GWLP_USERDATA);
struct win32_window *window = (struct win32_window *)GetWindowLongPtrW(hwnd, GWLP_USERDATA);
if (!window) {
return DefWindowProcA(hwnd, msg, wparam, lparam);
return DefWindowProcW(hwnd, msg, wparam, lparam);
}
LRESULT result = 0;
@ -834,7 +863,7 @@ INTERNAL LRESULT CALLBACK win32_window_proc(HWND hwnd, UINT msg, WPARAM wparam,
} break;
case WM_PAINT: {
result = DefWindowProcA(hwnd, msg, wparam, lparam);
result = DefWindowProcW(hwnd, msg, wparam, lparam);
} break;
case WM_MOVE:
@ -842,13 +871,13 @@ INTERNAL LRESULT CALLBACK win32_window_proc(HWND hwnd, UINT msg, WPARAM wparam,
case WM_SIZE:
case WM_SIZING: {
win32_update_window_from_system(window);
result = DefWindowProcA(hwnd, msg, wparam, lparam);
result = DefWindowProcW(hwnd, msg, wparam, lparam);
} break;
/* Keyboard buttons */
case WM_SYSKEYUP:
case WM_SYSKEYDOWN: {
result = DefWindowProcA(hwnd, msg, wparam, lparam);
result = DefWindowProcW(hwnd, msg, wparam, lparam);
} FALLTHROUGH;
case WM_KEYUP:
case WM_KEYDOWN: {
@ -997,7 +1026,7 @@ INTERNAL LRESULT CALLBACK win32_window_proc(HWND hwnd, UINT msg, WPARAM wparam,
default: {
result = DefWindowProcA(hwnd, msg, wparam, lparam);
result = DefWindowProcW(hwnd, msg, wparam, lparam);
} break;
}
@ -1476,7 +1505,7 @@ INTERNAL DWORD WINAPI win32_thread_proc(LPVOID params)
struct string thread_name = string_from_cstr(thread_params.thread_name_cstr);
if (thread_name.len > 0) {
struct temp_arena scratch = scratch_begin_no_conflict();
wchar_t *wc_thread_name = string_to_wstr(scratch.arena, thread_name);
wchar_t *wc_thread_name = wstr_from_string(scratch.arena, thread_name);
SetThreadDescription(GetCurrentThread(), wc_thread_name);
scratch_end(scratch);
}
@ -1509,7 +1538,7 @@ struct sys_thread sys_thread_init(sys_thread_func *thread_func, void *thread_dat
tp->thread_data = thread_data;
/* Copy thread name to params */
string_to_cstr_buff(thread_name, BUFFER_FROM_ARRAY(tp->thread_name_cstr));
cstr_buff_from_string(BUFFER_FROM_ARRAY(tp->thread_name_cstr), thread_name);
HANDLE handle = CreateThread(
NULL,
@ -1558,10 +1587,10 @@ void sys_thread_assert(u32 tid)
void sys_message_box(enum sys_message_box_kind kind, struct string message)
{
char message_buff[4096] = { 0 };
char *message_cstr = string_to_cstr_buff(message, BUFFER_FROM_ARRAY(message_buff));
struct temp_arena scratch = scratch_begin_no_conflict();
wchar_t *message_wstr = wstr_from_string(scratch.arena, message);
const char *title = "";
const wchar_t *title = L"";
UINT mbox_type = 0;
switch (kind) {
@ -1570,22 +1599,24 @@ void sys_message_box(enum sys_message_box_kind kind, struct string message)
} break;
case SYS_MESSAGE_BOX_KIND_WARNING: {
title = "Warning";
title = L"Warning";
mbox_type = MB_ICONWARNING;
} break;
case SYS_MESSAGE_BOX_KIND_ERROR: {
title = "Error";
title = L"Error";
mbox_type = MB_ICONERROR;
} break;
case SYS_MESSAGE_BOX_KIND_FATAL: {
title = "Fatal error";
title = L"Fatal error";
mbox_type = MB_ICONSTOP;
} break;
}
MessageBoxExA(NULL, message_cstr, title, mbox_type, 0);
MessageBoxExW(NULL, message_wstr, title, mbox_type, 0);
scratch_end(scratch);
}
/* ========================== *
@ -1650,21 +1681,30 @@ u32 sys_rand_u32(void)
return v;
}
void sys_panic_raw(char *msg_cstr)
INTERNAL void panic_exit(void)
{
/* FIXME: Exit other threads before showing message box */
MessageBoxExA(NULL, msg_cstr, "Fatal error", MB_ICONSTOP, 0);
ASSERT(false);
sys_exit();
}
void sys_panic_raw(char *msg_cstr)
{
/* FIXME: Exit other threads before showing message box */
MessageBoxExA(NULL, msg_cstr, "Fatal error", MB_ICONSTOP, 0);
panic_exit();
}
void sys_panic(struct string msg)
{
struct temp_arena scratch = scratch_begin_no_conflict();
/* FIXME: Exit other threads before showing message box */
logf_critical("Panicking: %F", FMT_STR(msg));
struct string prepend = STR("A fatal error has occured and the application needs to exit:\n\n");
msg = string_cat(scratch.arena, prepend, msg);
sys_panic_raw(string_to_cstr(scratch.arena, msg));
struct temp_arena scratch = scratch_begin_no_conflict();
msg = string_cat(scratch.arena,
STR("A fatal error has occured and the application needs to exit:\n\n"),
msg);
wchar_t *msg_wstr = wstr_from_string(scratch.arena, msg);
MessageBoxExW(NULL, msg_wstr, L"Fatal error", MB_ICONSTOP, 0);
panic_exit();
scratch_end(scratch);
}
@ -1782,14 +1822,14 @@ INTERNAL SYS_THREAD_FUNC_DEF(app_thread_entry_point, arg)
app_entry_point();
}
int CALLBACK WinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance, _In_ LPSTR command_line, _In_ int show_code)
int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance, _In_ LPWSTR command_line, _In_ int show_code)
{
(UNUSED)instance;
(UNUSED)prev_instance;
(UNUSED)command_line;
(UNUSED)show_code;
const char *error_msg = NULL;
const wchar_t *error_msg = NULL;
SetThreadDescription(GetCurrentThread(), L"Main thread");
@ -1816,7 +1856,7 @@ int CALLBACK WinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance,
L.thread_tls_index = TlsAlloc();
if (L.thread_tls_index == TLS_OUT_OF_INDEXES) {
/* TODO: GetLastError */
error_msg = "Platform initialization error: TLS_OUT_OF_INDEXES";
error_msg = L"Platform initialization error: TLS_OUT_OF_INDEXES";
goto error;
}
@ -1840,9 +1880,9 @@ int CALLBACK WinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance,
/* Create window class */
{
/* Register the window class */
WNDCLASSEX *wc = &L.window_class;
WNDCLASSEXW *wc = &L.window_class;
wc->cbSize = sizeof(WNDCLASSEX);
wc->lpszClassName = "power_play_window_class";
wc->lpszClassName = WINDOW_CLASS_NAME;
wc->hCursor = LoadCursor(NULL, IDC_ARROW);
wc->style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
//wc->hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
@ -1854,9 +1894,9 @@ int CALLBACK WinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance,
GetModuleFileName(instance, path, MAX_PATH);
ExtractIconEx(path, 0, &wc->hIcon, &wc->hIconSm, 1);
if (!RegisterClassExA(wc)) {
if (!RegisterClassExW(wc)) {
/* TODO: GetLastError */
error_msg = "Failed to register window class";
error_msg = L"Failed to register window class";
goto error;
}
}
@ -1871,14 +1911,14 @@ int CALLBACK WinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance,
if (!RegisterRawInputDevices(&rid, 1, sizeof(rid))) {
/* TODO: GetLastError */
error_msg = "Failed to register raw input device";
error_msg = L"Failed to register raw input device";
goto error;
}
}
error:
if (error_msg) {
MessageBoxExA(NULL, error_msg, "Fatal initialization error", MB_ICONSTOP, 0);
MessageBoxExW(NULL, error_msg, L"Fatal initialization error", MB_ICONSTOP, 0);
ASSERT(false);
return 1;
}
@ -1910,9 +1950,9 @@ __attribute((used))
int _fltused;
__attribute((used))
void __stdcall WinMainCRTStartup(void)
void __stdcall wWinMainCRTStartup(void)
{
int result = WinMain(GetModuleHandle(0), 0, GetCommandLineA(), 0);
int result = wWinMain(GetModuleHandle(0), 0, GetCommandLineW(), 0);
ExitProcess(result);
}

View File

@ -247,7 +247,7 @@ struct asset *texture_load_asset(struct string path, b32 help)
STR("Texture path \"%F\" too long!"),
FMT_STR(path)));
}
string_to_cstr_buff(path, BUFFER_FROM_ARRAY(params->path_cstr));
cstr_buff_from_string(BUFFER_FROM_ARRAY(params->path_cstr), path);
params->path_len = path.len;
params->asset = asset;