diff --git a/include/pgpl.h b/include/pgpl.h index 015e3ed..cbd9b13 100644 --- a/include/pgpl.h +++ b/include/pgpl.h @@ -2,7 +2,9 @@ #define PGPL_H #include +#include #include +#include #include #include #include diff --git a/include/pgpl/log.h b/include/pgpl/log.h new file mode 100644 index 0000000..5d36191 --- /dev/null +++ b/include/pgpl/log.h @@ -0,0 +1,27 @@ +#ifndef PGPL_LOG_H +#define PGPL_LOG_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum PGPL_LogLevel { + PGPL_LOG_LEVEL_DEBUG, + PGPL_LOG_LEVEL_INFO, + PGPL_LOG_LEVEL_WARN, + PGPL_LOG_LEVEL_ERROR, +} PGPL_LogLevel; + +void pgpl_log_set_minimum_level(PGPL_LogLevel level); + +void pgpl_log_output_file(FILE *file); + +void pgpl_log_message(PGPL_LogLevel level, const char *message, ...); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/pgpl/string.h b/include/pgpl/string.h new file mode 100644 index 0000000..5a22ad6 --- /dev/null +++ b/include/pgpl/string.h @@ -0,0 +1,18 @@ +#ifndef PGPL_STRING_H +#define PGPL_STRING_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Converts a string to a wide string, don't forget to call free() on the + * returned pointer. */ +wchar_t *pgpl_string_to_wide_string(const char *str); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/pgpl/window/predef.h b/include/pgpl/window/predef.h index 2a61482..b65ef5f 100644 --- a/include/pgpl/window/predef.h +++ b/include/pgpl/window/predef.h @@ -18,7 +18,7 @@ typedef struct PGPL_Window PGPL_Window; /* This is an input event which is returned on PGPL_WINDOW_EVENT_KEY_* and * PGPL_WINDOW_EVENT_MOUSE_* events. */ typedef struct PGPL_WindowInputEvent { - uint32_t key; + int32_t key; int32_t x; int32_t y; } PGPL_WindowInputEvent; diff --git a/meson.build b/meson.build index 1508407..ec059d5 100644 --- a/meson.build +++ b/meson.build @@ -22,6 +22,8 @@ lib = both_libraries( 'src/thread.c', 'src/timer.c', 'src/vector.c', + 'src/string.c', + 'src/log.c', 'src/window/window.c', 'src/window/window-x11.c', 'src/window/window-win32.c', diff --git a/src/gui/gui.c b/src/gui/gui.c index e45b328..6e2bbf2 100644 --- a/src/gui/gui.c +++ b/src/gui/gui.c @@ -1,6 +1,4 @@ - #include -#include #include static bool pgpl_gui_internal_event_loop(PGPL_Window *window, @@ -37,7 +35,8 @@ static bool pgpl_gui_internal_event_loop(PGPL_Window *window, pgpl_gui_destroy(gui, true); return false; } else if (event_type == PGPL_WINDOW_EVENT_ERROR) { - printf("PGPL_Window has experienced an unexpected error!\nExiting..."); + pgpl_log_message(PGPL_LOG_LEVEL_ERROR, + "PGPL_Window has experienced an unexpected error!"); } else { uint32_t width, height; uint32_t length = pgpl_vector_get_length(gui->widgets); diff --git a/src/gui/widgets/button.c b/src/gui/widgets/button.c index f88930a..33889d1 100644 --- a/src/gui/widgets/button.c +++ b/src/gui/widgets/button.c @@ -45,24 +45,21 @@ static void event(PGPL_GuiWidget *widget, PGPL_GuiTheme *theme, PGPL_Gui *gui, if (event_type == PGPL_WINDOW_EVENT_MOUSE_PRESS && event_data->input_event.key == PGPL_WINDOW_MOUSE_BUTTON_LEFT) { widget->gui_color = PGPL_GUI_STATUS_COLOR_ACTIVE; - return; } else if (event_type == PGPL_WINDOW_EVENT_MOUSE_RELEASE && event_data->input_event.key == PGPL_WINDOW_MOUSE_BUTTON_LEFT) { if (widget->gui_color == PGPL_GUI_STATUS_COLOR_ACTIVE) { button_widget->click_callback(gui->app_data); } widget->gui_color = PGPL_GUI_STATUS_COLOR_HOVER; - return; } else { if (widget->gui_color != PGPL_GUI_STATUS_COLOR_ACTIVE) { widget->gui_color = PGPL_GUI_STATUS_COLOR_HOVER; } - return; } + } else { + widget->gui_color = PGPL_GUI_STATUS_COLOR_NORMAL; } } - - widget->gui_color = PGPL_GUI_STATUS_COLOR_NORMAL; } static void destroy(PGPL_GuiWidget *widget) { diff --git a/src/log.c b/src/log.c new file mode 100644 index 0000000..3cd011c --- /dev/null +++ b/src/log.c @@ -0,0 +1,46 @@ +#include +#include +#include + +extern PGPL_Mutex *pgpl_internal_log_lock; + +extern FILE *pgpl_internal_log_file; + +static PGPL_LogLevel pgpl_log_internal_minimum_level = PGPL_LOG_LEVEL_ERROR; + +void pgpl_log_set_minimum_level(PGPL_LogLevel level) { + pgpl_log_internal_minimum_level = level; +} + +void pgpl_log_output_file(FILE *file) { pgpl_internal_log_file = file; } + +void pgpl_log_message(PGPL_LogLevel level, const char *format, ...) { + va_list args; + + va_start(args, format); + + pgpl_mutex_lock(pgpl_internal_log_lock); + if (level >= pgpl_log_internal_minimum_level) { + switch (level) { + case PGPL_LOG_LEVEL_DEBUG: + fprintf(pgpl_internal_log_file, "[DEBUG] "); + break; + case PGPL_LOG_LEVEL_INFO: + fprintf(pgpl_internal_log_file, "[INFO] "); + break; + case PGPL_LOG_LEVEL_WARN: + fprintf(pgpl_internal_log_file, "[WARN] "); + break; + case PGPL_LOG_LEVEL_ERROR: + fprintf(pgpl_internal_log_file, "[ERROR] "); + break; + } + + vfprintf(pgpl_internal_log_file, format, args); + fputc('\n', pgpl_internal_log_file); + } + + va_end(args); + + pgpl_mutex_unlock(pgpl_internal_log_lock); +} diff --git a/src/pgpl.c b/src/pgpl.c index 56fda58..bc498ae 100644 --- a/src/pgpl.c +++ b/src/pgpl.c @@ -1,7 +1,16 @@ #include -PGPL_Mutex *render_lock; +PGPL_Mutex *pgpl_internal_render_lock; +PGPL_Mutex *pgpl_internal_log_lock; +FILE *pgpl_internal_log_file; -void pgpl_init(void) { render_lock = pgpl_mutex_create(); } +void pgpl_init(void) { + pgpl_internal_render_lock = pgpl_mutex_create(); + pgpl_internal_log_lock = pgpl_mutex_create(); + pgpl_internal_log_file = stderr; +} -void pgpl_deinit(void) { pgpl_mutex_destroy(render_lock); } +void pgpl_deinit(void) { + pgpl_mutex_destroy(pgpl_internal_render_lock); + pgpl_mutex_destroy(pgpl_internal_log_lock); +} diff --git a/src/render/font.c b/src/render/font.c index 6ddfb23..1d06cef 100644 --- a/src/render/font.c +++ b/src/render/font.c @@ -9,10 +9,6 @@ #define STBTT_STATIC #include -#ifdef __WIN32__ -#include -#endif - #define CHAR_AMOUNT 256 #define BANK_AMOUNT 256 @@ -30,26 +26,6 @@ struct PGPL_Font { uint8_t *data; }; -/* Converts a string to a wide string, don't forget to call free() on the - * returned pointer. */ -static wchar_t *str_to_wstr(const char *str) { - size_t length = strlen(str); - wchar_t *wstr = malloc((length + 1) * sizeof(*wstr)); - - setlocale(LC_ALL, "en_US.UTF-8"); - - /* mbstowcs works just fine with UTF-8 strings on most platforms, except on - * Windows, where we have to use MultiByteToWideChar to do the exact same - * thing. */ -#if defined(__WIN32__) - MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, str, -1, wstr, length + 1); -#else - mbstowcs(wstr, str, length + 1); -#endif - - return wstr; -} - PGPL_Font *pgpl_font_create_from_file(const char *filename, uint32_t glyph_size) { PGPL_Font *font; @@ -58,7 +34,7 @@ PGPL_Font *pgpl_font_create_from_file(const char *filename, uint8_t *font_data; if (font_file == NULL) { - perror("Failed to open font"); + pgpl_log_message(PGPL_LOG_LEVEL_ERROR, "Failed to open font!"); return NULL; } @@ -158,7 +134,7 @@ void pgpl_font_render_glyph(PGPL_Renderer *renderer, PGPL_Font *font, wchar_t c, void pgpl_font_render_string(PGPL_Renderer *renderer, PGPL_Font *font, const char *str, PGPL_Color color, double x, double y, double size) { - wchar_t *wstr = str_to_wstr(str); + wchar_t *wstr = pgpl_string_to_wide_string(str); pgpl_font_render_wstring(renderer, font, wstr, color, x, y, size); @@ -213,11 +189,10 @@ void pgpl_font_glyph_dimensions(PGPL_Font *font, wchar_t c, double size, } /* Calculates the coordinates of an entire string. Also returns them in the - * passed pointers. - */ + * passed pointers. */ void pgpl_font_string_dimensions(PGPL_Font *font, const char *str, double size, PGPL_Rectangle *rectangle) { - wchar_t *wstr = str_to_wstr(str); + wchar_t *wstr = pgpl_string_to_wide_string(str); pgpl_font_wstring_dimensions(font, wstr, size, rectangle); diff --git a/src/render/texture.c b/src/render/texture.c index 9a8684f..871a721 100644 --- a/src/render/texture.c +++ b/src/render/texture.c @@ -19,7 +19,8 @@ pgpl_render_create_texture_file_memory(PGPL_Renderer *renderer, texture = pgpl_render_create_texture(renderer, data, x, y, filter, PGPL_TEXTURE_FORMAT_RGBA); } else { - fprintf(stderr, "Failed to open image: %s\n", stbi_failure_reason()); + pgpl_log_message(PGPL_LOG_LEVEL_ERROR, "Failed to open image: %s\n", + stbi_failure_reason()); return NULL; } @@ -38,7 +39,8 @@ PGPL_Texture *pgpl_render_create_texture_file(PGPL_Renderer *renderer, texture = pgpl_render_create_texture(renderer, data, x, y, filter, PGPL_TEXTURE_FORMAT_RGBA); } else { - fprintf(stderr, "Failed to open image: %s\n", stbi_failure_reason()); + pgpl_log_message(PGPL_LOG_LEVEL_ERROR, "Failed to open image: %s\n", + stbi_failure_reason()); return NULL; } diff --git a/src/string.c b/src/string.c new file mode 100644 index 0000000..4b83387 --- /dev/null +++ b/src/string.c @@ -0,0 +1,26 @@ +#include +#include +#include +#include + +#ifdef __WIN32__ +#include +#endif + +wchar_t *pgpl_string_to_wide_string(const char *str) { + size_t length = strlen(str); + wchar_t *wstr = malloc((length + 1) * sizeof(*wstr)); + + setlocale(LC_ALL, "en_US.UTF-8"); + + /* mbstowcs works just fine with UTF-8 strings on most platforms, except on + * Windows, where we have to use MultiByteToWideChar to do the exact same + * thing. */ +#if defined(__WIN32__) + MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, str, -1, wstr, length + 1); +#else + mbstowcs(wstr, str, length + 1); +#endif + + return wstr; +} diff --git a/src/window/internal.h b/src/window/internal.h index 6b86e43..426b078 100644 --- a/src/window/internal.h +++ b/src/window/internal.h @@ -5,7 +5,7 @@ /* This is needed if there are multiple windows open. Created by pgpl_init, * destroyed by pgpl_deinit. */ -extern PGPL_Mutex *render_lock; +extern PGPL_Mutex *pgpl_internal_render_lock; typedef struct PGPL_WindowShared { double scale; diff --git a/src/window/window-win32.c b/src/window/window-win32.c index d4883f0..0c29fe7 100644 --- a/src/window/window-win32.c +++ b/src/window/window-win32.c @@ -319,13 +319,13 @@ void pgpl_window_reparent_to(PGPL_Window *window, void *parent) { void *pgpl_window_get_raw_window(PGPL_Window *window) { return window->hwnd; } void pgpl_window_internal_start_render(PGPL_Window *window) { - pgpl_mutex_lock(render_lock); + pgpl_mutex_lock(pgpl_internal_render_lock); wglMakeCurrent(window->hdc, window->wgl_context); } void pgpl_window_internal_finish_render(PGPL_Window *window) { wglSwapLayerBuffers(window->hdc, WGL_SWAP_MAIN_PLANE); - pgpl_mutex_unlock(render_lock); + pgpl_mutex_unlock(pgpl_internal_render_lock); } #endif diff --git a/src/window/window-x11.c b/src/window/window-x11.c index ebf6928..1151e85 100644 --- a/src/window/window-x11.c +++ b/src/window/window-x11.c @@ -2,6 +2,7 @@ #include "internal.h" #include #include +#include #include struct PGPL_Window { @@ -144,10 +145,29 @@ void pgpl_window_set_position(PGPL_Window *window, int32_t x, int32_t y) { XFlush(window->display); } +static int32_t pgpl_window_internal_get_key(XKeyEvent *key_event) { + KeySym key_sym; + char buffer[32]; + wchar_t *wbuffer; + int32_t character = 0; + + int length = + XLookupString(key_event, buffer, sizeof(buffer) - 1, &key_sym, NULL); + + buffer[length] = '\0'; + + if (length != 0) { + wbuffer = pgpl_string_to_wide_string(buffer); + character = wbuffer[0]; + } else { + /* TODO: Handle control characters. */ + } + + return character; +} + /* This fetches the event from X11 and translates it to our own format, returns - * an Error if the Event was unknown. - * - * TODO: Translate the keymaps */ + * an Error if the Event was unknown. */ PGPL_WindowEventType pgpl_window_internal_fetch_window_event(PGPL_Window *window, PGPL_WindowEventData *event_data) { @@ -159,7 +179,7 @@ pgpl_window_internal_fetch_window_event(PGPL_Window *window, if (event_data != NULL) { event_data->input_event.x = event.xkey.x; event_data->input_event.y = event.xkey.y; - event_data->input_event.key = event.xkey.keycode; + event_data->input_event.key = pgpl_window_internal_get_key(&event.xkey); } return PGPL_WINDOW_EVENT_KEY_PRESS; break; @@ -167,7 +187,7 @@ pgpl_window_internal_fetch_window_event(PGPL_Window *window, if (event_data != NULL) { event_data->input_event.x = event.xkey.x; event_data->input_event.y = event.xkey.y; - event_data->input_event.key = event.xkey.keycode; + event_data->input_event.key = pgpl_window_internal_get_key(&event.xkey); } return PGPL_WINDOW_EVENT_KEY_RELEASE; break; @@ -221,12 +241,12 @@ void *pgpl_window_get_raw_window(PGPL_Window *window) { } void pgpl_window_internal_start_render(PGPL_Window *window) { - pgpl_mutex_lock(render_lock); + pgpl_mutex_lock(pgpl_internal_render_lock); glXMakeCurrent(window->display, window->window, window->glx_context); } void pgpl_window_internal_finish_render(PGPL_Window *window) { glXSwapBuffers(window->display, window->window); - pgpl_mutex_unlock(render_lock); + pgpl_mutex_unlock(pgpl_internal_render_lock); } #endif diff --git a/todo.md b/todo.md index acd4f70..f02dbe1 100644 --- a/todo.md +++ b/todo.md @@ -1,12 +1,13 @@ # TODO -Farther Blockers: -Translate keymaps properly so that they can be used by programs. -Further error handling on X11, Win32 API and more. -Logging library for this error handling, so that outputs can be supressed. (or remove the current prints...) +Win32 Blockers: +Translate keymaps on windows. +Fix the windows scrolling Fun Features: +- Further error handling on X11, Win32 API and more. +- Create some mappings for special keys - Allow not automatically freeing - get the framerate controllable and gettable, and then we can get animations. - Allow resizing the window with the scale.