diff options
Diffstat (limited to 'lib/liboda/src')
-rw-r--r-- | lib/liboda/src/input.c | 88 | ||||
-rw-r--r-- | lib/liboda/src/window.c | 206 |
2 files changed, 291 insertions, 3 deletions
diff --git a/lib/liboda/src/input.c b/lib/liboda/src/input.c new file mode 100644 index 0000000..797a9d4 --- /dev/null +++ b/lib/liboda/src/input.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2023-2025 Ian Marco Moffett and the Osmora Team. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Hyra nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/ascii.h> +#include <sys/errno.h> +#include <sys/param.h> +#include <liboda/oda.h> +#include <liboda/input.h> +#include <stdint.h> +#include <stdio.h> + +/* + * Convert key scancode/char values to fixed + * ODA key constants + */ +static inline uint16_t +oda_map_key(const struct oda_key *key) +{ + uint16_t type = ODA_KEY_OTHER; + + switch (key->ch) { + case ASCII_ESC: + type = ODA_KEY_ESCAPE; + break; + case ASCII_HT: + type = ODA_KEY_TAB; + break; + case ASCII_BS: + type = ODA_KEY_BACKSPACE; + break; + } + + return type; +} + +/* + * Dispatch keyboard events. This is typically + * called in an event loop so that keyboard events + * are handled per iteration. + * + * @kbd: Keyboard to monitor + */ +int +oda_kbd_dispatch(struct oda_kbd *kbd) +{ + struct oda_key key; + int input; + + if (kbd == NULL) { + return -EINVAL; + } + + /* Attempt to grab the input */ + if ((input = getchar()) < 0) { + return -EAGAIN; + } + + key.scancode = ODA_SCANCODE(input); + key.ch = ODA_KEYCHAR(input); + key.type = oda_map_key(&key); + return kbd->handle_keyev(kbd, &key); +} diff --git a/lib/liboda/src/window.c b/lib/liboda/src/window.c index 9a8b799..216b106 100644 --- a/lib/liboda/src/window.c +++ b/lib/liboda/src/window.c @@ -28,12 +28,121 @@ */ #include <sys/errno.h> +#include <sys/queue.h> #include <stdlib.h> #include <string.h> #include <liboda/oda.h> #include <liboda/odavar.h> #include <liboda/types.h> #include <libgfx/gfx.h> +#include <libgfx/draw.h> + +/* + * The window cache is used to reduce how many + * calls to malloc() and free() are made during + * window creation and destruction. + */ +static TAILQ_HEAD(, oda_window) wcache; +static uint32_t wcache_cookie = 0; +static odawid_t next_wid = 1; + +/* + * Pop a window from the window cache. + * Returns NULL there are no more windows. + */ +static struct oda_window * +oda_window_pop(void) +{ + struct oda_window *wdp; + + if (wcache_cookie != ODA_COOKIE) { + TAILQ_INIT(&wcache); + wcache_cookie = ODA_COOKIE; + return NULL; + } + + wdp = TAILQ_FIRST(&wcache); + TAILQ_REMOVE(&wcache, wdp, link); + return wdp; +} + +/* + * Place a window into the window cache. + */ +static void +oda_window_cache(struct oda_window *wdp) +{ + /* Ensure arg is valid */ + if (wdp == NULL) { + return; + } + + if (wcache_cookie != ODA_COOKIE) { + TAILQ_INIT(&wcache); + wcache_cookie = ODA_COOKIE; + } + + TAILQ_INSERT_TAIL(&wcache, wdp, link); +} + +/* + * Allocate an ODP window + * + * Returns NULL on failure + */ +static struct oda_window * +oda_window_alloc(void) +{ + struct oda_window *wdp; + + /* + * First check if there are any entries + * we can grab from the window cache. + */ + wdp = oda_window_pop(); + if (wdp != NULL) { + return wdp; + } + + /* Allocate a new window */ + wdp = malloc(sizeof(*wdp)); + if (wdp == NULL) { + return NULL; + } + + memset(wdp, 0, sizeof(*wdp)); + wdp->wid = next_wid++; + return wdp; +} + +/* + * Release a given ODA window descriptor + * + * @wdp: Window to free + */ +static void +oda_window_release(struct oda_state *state, struct oda_window *wdp) +{ + if (wdp == NULL) { + return; + } + + /* + * It is probably a good idea to ensure previous + * state other than the old window ID is reset + * and zeroed. + */ + wdp->session = NULL; + memset(&wdp->surface, 0, sizeof(wdp->surface)); + + /* + * Now we can remove this window from the list + * of windows we are tracking and add it to the + * cache. + */ + TAILQ_REMOVE(&state->winq, wdp, link); + oda_window_cache(wdp); +} /* * Check if a point is within the bounds of @@ -78,6 +187,34 @@ oda_check_point(struct oda_window *wp, struct oda_point *point) } /* + * Clean up after ourselves and release + * each entry of the wcache. + * + * Returns 0 on success. + */ +static int +oda_free_wcache(void) +{ + struct oda_window *wdp, *next; + + if (wcache_cookie != ODA_COOKIE) { + return -1; + } + + /* + * Go through each entry and call free() + * on them. + */ + wdp = TAILQ_FIRST(&wcache); + while (wdp != NULL) { + next = TAILQ_NEXT(wdp, link); + free(wdp); + wdp = next; + } + return 0; +} + +/* * Plot a pixel onto a window * * @state: ODA state pointer @@ -176,7 +313,7 @@ oda_reqwin(struct oda_wattr *params, struct oda_window **res) } /* Allocate a new window */ - wp = malloc(sizeof(*wp)); + wp = oda_window_alloc(); if (wp == NULL) { return -ENOMEM; } @@ -205,6 +342,61 @@ oda_reqwin(struct oda_wattr *params, struct oda_window **res) } /* + * Move a window to a new position on the + * screen. + * + * @state: ODA state pointer + * @params: Arguments to this function + */ +int +oda_movewin(struct oda_state *state, struct oda_movewin *params) +{ + struct oda_window *win; + struct gfx_shape *wsurf; + struct gfx_region r; + odadimm_t w, h; + odapos_t x, y, x_f, y_f; + odapos_t to_x, to_y; + uint32_t i = 0; + int error; + + /* Make sure arguments are valid */ + if (state == NULL || params == NULL) { + return -EINVAL; + } + + /* We need the window */ + if ((win = params->wp) == NULL) { + return -EINVAL; + } + + /* Verify state cookie */ + if ((error = oda_cookie_verify(state)) != 0) { + return error; + } + + wsurf = &win->surface; + to_x = params->to_x; + to_y = params->to_y; + + r.x = wsurf->x; + r.y = wsurf->y; + r.width = wsurf->width; + r.height = wsurf->height; + + /* + * We will copy the window to the new location and + * fill where the old window was with GFX_BLACK. + * + * TODO: Handle overlapping of windows + */ + gfx_copy_region(&state->gctx, &r, to_x, to_y); + wsurf->x = to_x; + wsurf->y = to_y; + return 0; +} + +/* * Register a window into the current ODA state. * Everytime a compositor requests a window, we * must keep track of it. @@ -255,7 +447,15 @@ oda_termwin(struct oda_state *state, struct oda_window *win) return error; } - TAILQ_REMOVE(&state->winq, win, link); - free(win); + oda_window_release(state, win); return 0; } + +/* + * Shutdown the ODA library + */ +int +oda_shutdown(struct oda_state *state) +{ + return oda_free_wcache(); +} |