aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2021-11-15 08:49:34 +0100
committerdec05eba <dec05eba@protonmail.com>2021-11-15 09:01:05 +0100
commitb6ceb4af109f26885c91f01d0a63593158e567fa (patch)
tree441e784a9715d6c180c805854a5ee148b3219ef0
parenta3c6774f211ee765f910df76837548bdadd4e959 (diff)
Window: add close, title, cursor visibility and framerate limit
-rw-r--r--include/mgl/window/window.h9
-rw-r--r--src/window/window.c118
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 <stdbool.h>
@@ -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 <X11/Xutil.h>
+#include <X11/cursorfont.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
+#include <unistd.h>
/* 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;
+}