From b6ceb4af109f26885c91f01d0a63593158e567fa Mon Sep 17 00:00:00 2001 From: dec05eba Date: Mon, 15 Nov 2021 08:49:34 +0100 Subject: Window: add close, title, cursor visibility and framerate limit --- include/mgl/window/window.h | 9 ++++ src/window/window.c | 118 +++++++++++++++++++++++++++++++++++++------- 2 files changed, 110 insertions(+), 17 deletions(-) diff --git a/include/mgl/window/window.h b/include/mgl/window/window.h index c6fce87..aa516a8 100644 --- a/include/mgl/window/window.h +++ b/include/mgl/window/window.h @@ -3,6 +3,7 @@ #include "../graphics/color.h" #include "../system/vec.h" +#include "../system/clock.h" #include "key.h" #include @@ -27,6 +28,8 @@ struct mgl_window { mgl_vec2i cursor_position; mgl_view view; bool open; + double frame_time_limit; + mgl_clock frame_timer; }; int mgl_window_create(mgl_window *self, const char *title, int width, int height); @@ -51,4 +54,10 @@ void mgl_window_get_view(mgl_window *self, mgl_view *view); bool mgl_window_is_open(const mgl_window *self); bool mgl_window_is_key_pressed(const mgl_window *self, mgl_key key); +void mgl_window_close(mgl_window *self); +void mgl_window_set_title(mgl_window *self, const char *title); +void mgl_window_set_cursor_visible(mgl_window *self, bool visible); +/* 0 = no fps limit */ +void mgl_window_set_framerate_limit(mgl_window *self, int fps); + #endif /* MGL_WINDOW_H */ diff --git a/src/window/window.c b/src/window/window.c index 4d72635..f743ef0 100644 --- a/src/window/window.c +++ b/src/window/window.c @@ -3,10 +3,12 @@ #include "../../include/mgl/mgl.h" #include "../../include/mgl/system/utf8.h" #include +#include #include #include #include #include +#include /* TODO: Handle XIM better. Set XIM position to text position on screen (for text input) and reset input when selecting a new text input, etc */ @@ -50,6 +52,8 @@ typedef struct { GLXContext glx_context; XIM xim; XIC xic; + Cursor default_cursor; + Cursor invisible_cursor; /* Used to stack text event on top of key press/release events and other text events. For example pressing a key should give the user both key press and text events @@ -60,15 +64,72 @@ typedef struct { bool key_pressed[__MGL_NUM_KEYS__]; } x11_context; -static void x11_context_init(x11_context *self) { +static void x11_context_deinit(x11_context *self); + +static int x11_context_init(x11_context *self) { + mgl_context *context = mgl_get_context(); + self->glx_context = NULL; self->xim = NULL; self->xic = NULL; + self->default_cursor = None; + self->invisible_cursor = None; + + self->default_cursor = XCreateFontCursor(context->connection, XC_arrow); + if(!self->default_cursor) { + x11_context_deinit(self); + return -1; + } + + const char data[1] = {0}; + Pixmap blank_bitmap = XCreateBitmapFromData(context->connection, DefaultRootWindow(context->connection), data, 1, 1); + if(!blank_bitmap) + return -1; + + XColor dummy; + self->invisible_cursor = XCreatePixmapCursor(context->connection, blank_bitmap, blank_bitmap, &dummy, &dummy, 0, 0); + XFreePixmap(context->connection, blank_bitmap); + if(!self->invisible_cursor) { + x11_context_deinit(self); + return -1; + } + x11_events_circular_buffer_init(&self->events); for(size_t i = 0; i < __MGL_NUM_KEYS__; ++i) { self->key_pressed[i] = false; } + + return 0; +} + +void x11_context_deinit(x11_context *self) { + mgl_context *context = mgl_get_context(); + + if(self->invisible_cursor) { + XFreeCursor(context->connection, self->invisible_cursor); + self->invisible_cursor = None; + } + + if(self->default_cursor) { + XFreeCursor(context->connection, self->default_cursor); + self->default_cursor = None; + } + + if(self->xic) { + XDestroyIC(self->xic); + self->xic = NULL; + } + + if(self->xim) { + XCloseIM(self->xim); + self->xim = NULL; + } + + if(self->glx_context) { + context->gl.glXDestroyContext(context->connection, self->glx_context); + self->glx_context = NULL; + } } static bool x11_context_append_event(x11_context *self, const mgl_event *event) { @@ -136,6 +197,8 @@ static int mgl_window_init(mgl_window *self, const char *title, int width, int h self->window = 0; self->context = NULL; self->open = false; + self->frame_time_limit = 0.0; + mgl_clock_init(&self->frame_timer); self->context = malloc(sizeof(x11_context)); if(!self->context) { @@ -144,7 +207,11 @@ static int mgl_window_init(mgl_window *self, const char *title, int width, int h } x11_context *x11_context = self->context; - x11_context_init(x11_context); + if(x11_context_init(x11_context) != 0) { + fprintf(stderr, "x11_context_init failed\n"); + mgl_window_deinit(self); + return -1; + } mgl_context *context = mgl_get_context(); @@ -261,21 +328,7 @@ void mgl_window_deinit(mgl_window *self) { mgl_context *context = mgl_get_context(); x11_context *x11_context = self->context; if(x11_context) { - if(x11_context->xic) { - XDestroyIC(x11_context->xic); - x11_context->xic = NULL; - } - - if(x11_context->xim) { - XCloseIM(x11_context->xim); - x11_context->xim = NULL; - } - - if(x11_context->glx_context) { - context->gl.glXDestroyContext(context->connection, x11_context->glx_context); - x11_context->glx_context = NULL; - } - + x11_context_deinit(x11_context); free(x11_context); self->context = NULL; } @@ -497,6 +550,13 @@ bool mgl_window_poll_event(mgl_window *self, mgl_event *event) { void mgl_window_display(mgl_window *self) { mgl_context *context = mgl_get_context(); context->gl.glXSwapBuffers(context->connection, self->window); + + if(self->frame_time_limit > 0.000001) { + double time_left_to_sleep = self->frame_time_limit - mgl_clock_get_elapsed_time_seconds(&self->frame_timer); + if(time_left_to_sleep > 0.0) + usleep(time_left_to_sleep * 1000000.0); + mgl_clock_restart(&self->frame_timer); + } } void mgl_window_set_view(mgl_window *self, mgl_view *new_view) { @@ -522,3 +582,27 @@ bool mgl_window_is_key_pressed(const mgl_window *self, mgl_key key) { return false; return x11_context_is_key_pressed(self->context, key); } + +void mgl_window_close(mgl_window *self) { + mgl_context *context = mgl_get_context(); + XDestroyWindow(context->connection, self->window); + self->open = false; +} + +void mgl_window_set_title(mgl_window *self, const char *title) { + mgl_context *context = mgl_get_context(); + XStoreName(context->connection, self->window, title); +} + +void mgl_window_set_cursor_visible(mgl_window *self, bool visible) { + mgl_context *context = mgl_get_context(); + x11_context *x11_context = self->context; + XDefineCursor(context->connection, self->window, visible ? x11_context->default_cursor : x11_context->invisible_cursor); +} + +void mgl_window_set_framerate_limit(mgl_window *self, int fps) { + if(fps <= 0) + self->frame_time_limit = 0.0; + else + self->frame_time_limit = 1.0 / fps; +} -- cgit v1.2.3