Added logging and X11 Keymap translation. Also various bugfixes.

This commit is contained in:
Patrick 2025-10-04 16:38:45 +02:00
commit 54a0f5eb4e
16 changed files with 181 additions and 57 deletions

View file

@ -2,7 +2,9 @@
#define PGPL_H
#include <pgpl/gui.h>
#include <pgpl/log.h>
#include <pgpl/render.h>
#include <pgpl/string.h>
#include <pgpl/thread.h>
#include <pgpl/timer.h>
#include <pgpl/vector.h>

27
include/pgpl/log.h Normal file
View file

@ -0,0 +1,27 @@
#ifndef PGPL_LOG_H
#define PGPL_LOG_H
#include <stdio.h>
#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

18
include/pgpl/string.h Normal file
View file

@ -0,0 +1,18 @@
#ifndef PGPL_STRING_H
#define PGPL_STRING_H
#include <wchar.h>
#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

View file

@ -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;

View file

@ -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',

View file

@ -1,6 +1,4 @@
#include <pgpl.h>
#include <stdio.h>
#include <stdlib.h>
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);

View file

@ -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;
}
}
}
static void destroy(PGPL_GuiWidget *widget) {

46
src/log.c Normal file
View file

@ -0,0 +1,46 @@
#include <pgpl.h>
#include <stdarg.h>
#include <stdio.h>
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);
}

View file

@ -1,7 +1,16 @@
#include <pgpl.h>
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);
}

View file

@ -9,10 +9,6 @@
#define STBTT_STATIC
#include <stb/stb_truetype.h>
#ifdef __WIN32__
#include <windows.h>
#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);

View file

@ -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;
}

26
src/string.c Normal file
View file

@ -0,0 +1,26 @@
#include <locale.h>
#include <pgpl.h>
#include <stdlib.h>
#include <string.h>
#ifdef __WIN32__
#include <windows.h>
#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;
}

View file

@ -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;

View file

@ -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

View file

@ -2,6 +2,7 @@
#include "internal.h"
#include <GL/glx.h>
#include <X11/Xlib.h>
#include <stdio.h>
#include <stdlib.h>
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

View file

@ -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.