unicode support in win32 layer
This commit is contained in:
parent
db16c4b067
commit
9a8b712f98
@ -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
|
||||
* ========================== */
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
struct resource {
|
||||
struct buffer bytes;
|
||||
|
||||
/* Internal */
|
||||
#if !RESOURCES_EMBEDDED
|
||||
struct sys_file file;
|
||||
struct sys_file_map file_map;
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
231
src/string.c
231
src/string.c
@ -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
|
||||
};
|
||||
}
|
||||
|
||||
27
src/string.h
27
src/string.h
@ -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
|
||||
|
||||
20
src/sys.h
20
src/sys.h
@ -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
|
||||
|
||||
278
src/sys_win32.c
278
src/sys_win32.c
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user