diff options
Diffstat (limited to 'src/main/engine/ui/x11/ui.c')
-rw-r--r-- | src/main/engine/ui/x11/ui.c | 201 |
1 files changed, 201 insertions, 0 deletions
diff --git a/src/main/engine/ui/x11/ui.c b/src/main/engine/ui/x11/ui.c new file mode 100644 index 0000000..76adaac --- /dev/null +++ b/src/main/engine/ui/x11/ui.c @@ -0,0 +1,201 @@ +/*- + * Copyright (C) 2025 Alessandro Iezzi <aiezzi AT alessandroiezzi PERIOD it> + * + * This file is part of Tris Game. + * + * Tris Game is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tris Game is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tris Game. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <GL/gl.h> +#include <GL/glx.h> +#include <X11/Xlib.h> +#include <unistd.h> +#include <time.h> +#include "../../../util.h" + +static Display *display; +static Window window; +static GLXContext gl_context; +static int close_window = 0; + +void (*on_loop_event)(); +void (*on_mouse_press_event)(); +void (*on_generic_event)(int); + +void cleanup(void); + +static Display * +ui_open_display(void) +{ + Display *display = XOpenDisplay(NULL); + if (!display) { + log_error("Can't open X11 display"); + exit(1); + } + + return display; +} + +static XVisualInfo * +gl_choose_visual(int screen) +{ + GLint attribs[] = { GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None }; + XVisualInfo *vi = glXChooseVisual(display, screen, attribs); + if (!vi) { + log_error("No compatible Visual found"); + exit(1); + } + + return vi; +} + +static XSetWindowAttributes +ui_get_attributes(Window root, XVisualInfo *vi) +{ + Colormap colormap = XCreateColormap(display, root, vi->visual, AllocNone); + XSetWindowAttributes swa; + swa.colormap = colormap; + swa.event_mask = ExposureMask | KeyPressMask | StructureNotifyMask | ButtonPressMask | ButtonReleaseMask; + + return swa; +} + +static Window +ui_create_window(Window root, XVisualInfo *vi, int width, int height) +{ + XSetWindowAttributes swa = ui_get_attributes(root, vi); + Window window = XCreateWindow(display, root, 0, 0, width, height, 0, vi->depth, InputOutput, vi->visual, + CWColormap | CWEventMask, &swa); + XMapWindow(display, window); + + return window; +} + +void +ui_set_title(const char *title) +{ + XStoreName(display, window, title); +} + +void +ui_init(int width, int height) +{ + display = ui_open_display(); + + int screen = DefaultScreen(display); + Window root = RootWindow(display, screen); + + XVisualInfo *vi = gl_choose_visual(screen); + window = ui_create_window(root, vi, width, height); + + gl_context = glXCreateContext(display, vi, NULL, GL_TRUE); + + if (!glXMakeCurrent(display, window, gl_context)) { + log_error("Error on making GLX context"); + exit(1); + } +} + +static void +ui_on_expose(XEvent event) +{ + if (event.type != Expose) return; +} + +static void +ui_on_resize(XEvent event) +{ + if (event.type != ConfigureNotify) return; + glViewport(0, 0, event.xconfigure.width, event.xconfigure.height); +} + +static void +ui_on_keypress(XEvent event) +{ + if (event.type != KeyPress) return; + close_window = 1; +} + +static void +ui_on_mouse_press(XEvent event) +{ + if (event.type != ButtonPress) return; + if (on_mouse_press_event != NULL) { + on_mouse_press_event(); + } +} + +static void +ui_on_mouse_release(XEvent event) +{ + if (event.type != ButtonRelease) return; +} + +static void +ui_on_generic_event(XEvent event) +{ + if (on_generic_event != NULL) { + on_generic_event(event.type); + } +} + +void +ui_set_loop_listener(void (*loop_event)()) +{ + on_loop_event = loop_event; +} + +void +ui_set_mouse_press_listener(void (*mouse_press_event)()) +{ + on_mouse_press_event = mouse_press_event; +} + +void +ui_set_generic_listener(void (*generic_event)(int type)) +{ + on_generic_event = generic_event; +} + +void +ui_loop(void) +{ + XEvent event; + while (!close_window) { + while (XPending(display)) { + XNextEvent(display, &event); + ui_on_generic_event(event); + ui_on_expose(event); + ui_on_resize(event); + ui_on_keypress(event); + ui_on_mouse_press(event); + ui_on_mouse_release(event); + } + + on_loop_event(); + glXSwapBuffers(display, window); + } + + cleanup(); +} + +void +cleanup(void) { + glXMakeCurrent(display, None, NULL); + glXDestroyContext(display, gl_context); + XDestroyWindow(display, window); + XCloseDisplay(display); +} |