ltk

Socket-based GUI for X11 (WIP)
git clone git://lumidify.org/ltk.git (fast, but not encrypted)
git clone https://lumidify.org/git/ltk.git (encrypted, but very slow)
Log | Files | Refs | README | LICENSE

commit 994e235d9939788238dd2c66cdefb4cc4ade1bce
parent 3a21eba1783e1d29204d54e006fe9f5efb016fc3
Author: lumidify <nobody@lumidify.org>
Date:   Sun,  5 Jun 2022 23:45:33 +0200

Abstract event handling a bit

Diffstat:
MMakefile | 7+++++--
Msrc/box.c | 36+++++++++++++++++-------------------
Msrc/button.c | 10++++------
Dsrc/color.c | 53-----------------------------------------------------
Msrc/color.h | 8++++++--
Asrc/color_xlib.c | 47+++++++++++++++++++++++++++++++++++++++++++++++
Asrc/event.h | 96+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/event_xlib.c | 80+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/graphics.h | 20+++++++++++++++-----
Msrc/graphics_xlib.c | 179+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
Msrc/grid.c | 32+++++++++++++-------------------
Msrc/label.c | 4+---
Msrc/ltk.h | 44+++++++++++++++++---------------------------
Msrc/ltkd.c | 193++++++++++++++++++++-----------------------------------------------------------
Msrc/memory.c | 3---
Msrc/menu.c | 52+++++++++++++++++++++++++---------------------------
Msrc/scrollbar.c | 25+++++++++++++------------
Msrc/surface_cache.c | 13+++++++------
Msrc/surface_cache.h | 2+-
Msrc/text.h | 1+
Msrc/text_pango.c | 3++-
Msrc/text_stb.c | 5+++--
Msrc/theme.c | 8+++++---
Msrc/theme.h | 1+
Msrc/widget.c | 12+++++-------
Msrc/widget.h | 25+++++++++++++------------
Asrc/xlib_shared.h | 20++++++++++++++++++++
27 files changed, 594 insertions(+), 385 deletions(-)

diff --git a/Makefile b/Makefile @@ -39,7 +39,7 @@ OBJ = \ src/strtonum.o \ src/util.o \ src/memory.o \ - src/color.o \ + src/color_xlib.o \ src/rect.o \ src/widget.o \ src/ltkd.o \ @@ -53,6 +53,7 @@ OBJ = \ src/theme.o \ src/graphics_xlib.o \ src/surface_cache.o \ + src/event_xlib.o \ $(EXTRA_OBJ) # src/draw.o \ @@ -79,7 +80,9 @@ HDR = \ src/theme.h \ src/graphics.h \ src/surface_cache.h \ - src/macros.h + src/macros.h \ + src/event.h \ + src/xlib_shared.h # src/draw.h \ all: src/ltkd src/ltkc diff --git a/src/box.c b/src/box.c @@ -20,9 +20,7 @@ #include <stdint.h> #include <string.h> -#include <X11/Xlib.h> -#include <X11/Xutil.h> - +#include "event.h" #include "memory.h" #include "color.h" #include "rect.h" @@ -42,10 +40,10 @@ static int ltk_box_add(ltk_window *window, ltk_widget *widget, ltk_box *box, uns static int ltk_box_remove(ltk_window *window, ltk_widget *widget, ltk_widget *self, char **errstr); /* static int ltk_box_clear(ltk_window *window, ltk_box *box, int shallow, char **errstr); */ static void ltk_box_scroll(ltk_widget *self); -static int ltk_box_mouse_event(ltk_box *box, XEvent event, void (*handler)(ltk_widget *, XEvent)); -static int ltk_box_mouse_press(ltk_widget *self, XEvent event); -static int ltk_box_mouse_release(ltk_widget *self, XEvent event); -static int ltk_box_motion_notify(ltk_widget *self, XEvent event); +static int ltk_box_mouse_event(ltk_box *box, int x, int y, ltk_event *event, void (*handler)(ltk_widget *, ltk_event *)); +static int ltk_box_mouse_press(ltk_widget *self, ltk_event *event); +static int ltk_box_mouse_release(ltk_widget *self, ltk_event *event); +static int ltk_box_motion_notify(ltk_widget *self, ltk_event *event); static struct ltk_widget_vtable vtable = { .change_state = NULL, @@ -324,10 +322,10 @@ ltk_box_scroll(ltk_widget *self) { } static int -ltk_box_mouse_event(ltk_box *box, XEvent event, void (*handler)(ltk_widget *, XEvent)) { +ltk_box_mouse_event(ltk_box *box, int x, int y, ltk_event *event, void (*handler)(ltk_widget *, ltk_event *)) { ltk_widget *widget; - if (ltk_collide_rect(box->sc->widget.rect, event.xbutton.x, event.xbutton.y)) { + if (ltk_collide_rect(box->sc->widget.rect, x, y)) { handler((ltk_widget *)box->sc, event); return 0; } @@ -335,7 +333,7 @@ ltk_box_mouse_event(ltk_box *box, XEvent event, void (*handler)(ltk_widget *, XE /* FIXME: check only the currently visible items */ for (size_t i = 0; i < box->num_widgets; i++) { widget = box->widgets[i]; - if (ltk_collide_rect(widget->rect, event.xbutton.x, event.xbutton.y)) { + if (ltk_collide_rect(widget->rect, x, y)) { handler(widget, event); return 0; } @@ -344,41 +342,41 @@ ltk_box_mouse_event(ltk_box *box, XEvent event, void (*handler)(ltk_widget *, XE } static int -ltk_box_mouse_press(ltk_widget *self, XEvent event) { +ltk_box_mouse_press(ltk_widget *self, ltk_event *event) { ltk_box *box = (ltk_box *)self; /* FIXME: combine multiple events into one for efficiency */ /* FIXME: fix this whole state handling */ - if (event.xbutton.button == 4 || event.xbutton.button == 5) { + if (event->button.button == LTK_BUTTON4 || event->button.button == LTK_BUTTON5) { ltk_widget *widget; int default_handler = 1; for (size_t i = 0; i < box->num_widgets; i++) { widget = box->widgets[i]; - if (ltk_collide_rect(widget->rect, event.xbutton.x, event.xbutton.y)) { + if (ltk_collide_rect(widget->rect, event->button.x, event->button.y)) { if (widget->vtable->mouse_press) default_handler = widget->vtable->mouse_press(widget, event); } } /* FIXME: configure scrollstep */ if (default_handler) { - int delta = event.xbutton.button == 4 ? -15 : 15; + int delta = event->button.button == LTK_BUTTON4 ? -15 : 15; ltk_scrollbar_scroll((ltk_widget *)box->sc, delta, 0); } return 0; } else { - return ltk_box_mouse_event(box, event, &ltk_widget_mouse_press_event); + return ltk_box_mouse_event(box, event->button.x, event->button.y, event, &ltk_widget_mouse_press_event); } } static int -ltk_box_mouse_release(ltk_widget *self, XEvent event) { +ltk_box_mouse_release(ltk_widget *self, ltk_event *event) { ltk_box *box = (ltk_box *)self; - return ltk_box_mouse_event(box, event, &ltk_widget_mouse_release_event); + return ltk_box_mouse_event(box, event->button.x, event->button.y, event, &ltk_widget_mouse_release_event); } static int -ltk_box_motion_notify(ltk_widget *self, XEvent event) { +ltk_box_motion_notify(ltk_widget *self, ltk_event *event) { ltk_box *box = (ltk_box *)self; - return ltk_box_mouse_event(box, event, &ltk_widget_motion_notify_event); + return ltk_box_mouse_event(box, event->motion.x, event->motion.y, event, &ltk_widget_motion_notify_event); } /* box <box id> add <widget id> [sticky] */ diff --git a/src/button.c b/src/button.c @@ -20,9 +20,7 @@ #include <string.h> #include <stdarg.h> -#include <X11/Xlib.h> -#include <X11/Xutil.h> - +#include "event.h" #include "memory.h" #include "color.h" #include "rect.h" @@ -39,7 +37,7 @@ #define MAX_BUTTON_PADDING 500 static void ltk_button_draw(ltk_widget *self, ltk_rect clip); -static int ltk_button_mouse_release(ltk_widget *self, XEvent event); +static int ltk_button_mouse_release(ltk_widget *self, ltk_event *event); static ltk_button *ltk_button_create(ltk_window *window, const char *id, char *text); static void ltk_button_destroy(ltk_widget *self, int shallow); @@ -171,9 +169,9 @@ ltk_button_change_state(ltk_widget *self) { /* FIXME: only when pressed button was actually this one */ static int -ltk_button_mouse_release(ltk_widget *self, XEvent event) { +ltk_button_mouse_release(ltk_widget *self, ltk_event *event) { ltk_button *button = (ltk_button *)self; - if (event.xbutton.button == 1) { + if (event->button.button == LTK_BUTTONL) { ltk_queue_event(button->widget.window, LTK_EVENT_BUTTON, button->widget.id, "button_click"); return 1; } diff --git a/src/color.c b/src/color.c @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2021 lumidify <nobody@lumidify.org> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <stdarg.h> -#include <X11/Xlib.h> -#include <X11/Xutil.h> - -#include "util.h" -#include "color.h" -#include "compat.h" - -/* FIXME: avoid initializing part of the struct and then error returning */ -/* FIXME: better error codes */ -/* FIXME: I think xcolor is unneeded when xft is enabled */ -int -ltk_color_create(Display *dpy, Visual *vis, Colormap cm, const char *hex, ltk_color *col) { - if (!XParseColor(dpy, cm, hex, &col->xcolor)) - return 1; - if (!XAllocColor(dpy, cm, &col->xcolor)) - return 1; - /* FIXME: replace with XftColorAllocValue */ - #if USE_XFT == 1 - if (!XftColorAllocName(dpy, vis, cm, hex, &col->xftcolor)) - return 1; - #else - (void)vis; - #endif - return 0; -} - -void -ltk_color_destroy(Display *dpy, Visual *vis, Colormap cm, ltk_color *col) { - /* FIXME: what should the 'planes' argument be? */ - XFreeColors(dpy, cm, &col->xcolor.pixel, 1, 0); - #if USE_XFT == 1 - XftColorFree(dpy, vis, cm, &col->xftcolor); - #else - (void)vis; - #endif -} diff --git a/src/color.h b/src/color.h @@ -23,6 +23,9 @@ #include <X11/Xft/Xft.h> #endif +/* FIXME: proper compilation option */ +#include <X11/Xlib.h> + typedef struct { XColor xcolor; #if USE_XFT == 1 @@ -30,8 +33,9 @@ typedef struct { #endif } ltk_color; +#include "graphics.h" /* returns 1 on failure, 0 on success */ -int ltk_color_create(Display *dpy, Visual *vis, Colormap cm, const char *hex, ltk_color *col); -void ltk_color_destroy(Display *dpy, Visual *vis, Colormap cm, ltk_color *col); +int ltk_color_create(ltk_renderdata *renderdata, const char *hex, ltk_color *col); +void ltk_color_destroy(ltk_renderdata *renderdata, ltk_color *col); #endif /* _LTK_COLOR_H_ */ diff --git a/src/color_xlib.c b/src/color_xlib.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2021, 2022 lumidify <nobody@lumidify.org> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <stdarg.h> +#include "util.h" +#include "color.h" +#include "compat.h" +#include "xlib_shared.h" + +/* FIXME: avoid initializing part of the struct and then error returning */ +/* FIXME: better error codes */ +/* FIXME: I think xcolor is unneeded when xft is enabled */ +int +ltk_color_create(ltk_renderdata *renderdata, const char *hex, ltk_color *col) { + if (!XParseColor(renderdata->dpy, renderdata->cm, hex, &col->xcolor)) + return 1; + if (!XAllocColor(renderdata->dpy, renderdata->cm, &col->xcolor)) + return 1; + /* FIXME: replace with XftColorAllocValue */ + #if USE_XFT == 1 + if (!XftColorAllocName(renderdata->dpy, renderdata->vis, renderdata->cm, hex, &col->xftcolor)) + return 1; + #endif + return 0; +} + +void +ltk_color_destroy(ltk_renderdata *renderdata, ltk_color *col) { + /* FIXME: what should the 'planes' argument be? */ + XFreeColors(renderdata->dpy, renderdata->cm, &col->xcolor.pixel, 1, 0); + #if USE_XFT == 1 + XftColorFree(renderdata->dpy, renderdata->vis, renderdata->cm, &col->xftcolor); + #endif +} diff --git a/src/event.h b/src/event.h @@ -0,0 +1,96 @@ +#ifndef LTK_EVENT_H +#define LTK_EVENT_H + +typedef enum { + LTK_UNKNOWN_EVENT, /* FIXME: a bit weird */ + LTK_BUTTONPRESS_EVENT, + LTK_BUTTONRELEASE_EVENT, + LTK_MOTION_EVENT, + LTK_KEYPRESS_EVENT, + LTK_KEYRELEASE_EVENT, + LTK_CONFIGURE_EVENT, + LTK_EXPOSE_EVENT, + LTK_WINDOWCLOSE_EVENT +} ltk_event_type; + +/* FIXME: button mask also in motion */ + +typedef enum { + LTK_BUTTONL, + LTK_BUTTONM, + LTK_BUTTONR, + /* FIXME: dedicated scroll event */ + LTK_BUTTON4, + LTK_BUTTON5, + LTK_BUTTON6, + LTK_BUTTON7 +} ltk_button_type; + +typedef struct { + ltk_event_type type; + ltk_button_type button; + int x, y; +} ltk_button_event; + +typedef struct { + ltk_event_type type; + int x, y; +} ltk_motion_event; + +/* FIXME: just steal the definitions from X when using Xlib so no conversion is necessary? */ +typedef enum { + LTK_KEY_NONE = 0, + LTK_KEY_LEFT, + LTK_KEY_RIGHT, + LTK_KEY_UP, + LTK_KEY_DOWN, + LTK_KEY_BACKSPACE, + LTK_KEY_DELETE, + LTK_KEY_SPACE, + LTK_KEY_RETURN +} ltk_keysym; + +typedef enum { + LTK_MOD_CTRL, + LTK_MOD_SHIFT, + LTK_MOD_ALT, + LTK_MOD_SUPER +} ltk_mod_type; + +typedef struct { + ltk_event_type type; + int x, y; + ltk_mod_type modmask; + ltk_keysym sym; + char *text; + char *mapped; +} ltk_key_event; + +typedef struct { + ltk_event_type type; + int x, y; + int w, h; +} ltk_configure_event; + +/* FIXME: should maybe be handled in backend with double buffering */ +typedef struct { + ltk_event_type type; + int x, y; + int w, h; +} ltk_expose_event; + +typedef union { + ltk_event_type type; + ltk_button_event button; + ltk_motion_event motion; + ltk_key_event key; + ltk_configure_event configure; + ltk_expose_event expose; +} ltk_event; + +#include "ltk.h" + +int ltk_events_pending(ltk_renderdata *renderdata); +void ltk_next_event(ltk_renderdata *renderdata, ltk_event *event); + +#endif /* LTK_EVENT_H */ diff --git a/src/event_xlib.c b/src/event_xlib.c @@ -0,0 +1,80 @@ +#include "graphics.h" +#include "xlib_shared.h" + +int +ltk_events_pending(ltk_renderdata *renderdata) { + return XPending(renderdata->dpy); +} + +static ltk_button_type +get_button(unsigned int button) { + switch (button) { + case Button1: return LTK_BUTTONL; + case Button2: return LTK_BUTTONM; + case Button3: return LTK_BUTTONR; + case 4: return LTK_BUTTON4; + case 5: return LTK_BUTTON5; + case 6: return LTK_BUTTON6; + case 7: return LTK_BUTTON7; + default: return LTK_BUTTONL; /* FIXME: what to do here? */ + } +} + +void +ltk_next_event(ltk_renderdata *renderdata, ltk_event *event) { + XEvent xevent; + XNextEvent(renderdata->dpy, &xevent); + *event = (ltk_event){.type = LTK_UNKNOWN_EVENT}; + switch (xevent.type) { + case ButtonPress: + *event = (ltk_event){.button = { + .type = LTK_BUTTONPRESS_EVENT, + .button = get_button(xevent.xbutton.button), + .x = xevent.xbutton.x, + .y = xevent.xbutton.y + }}; + break; + case ButtonRelease: + *event = (ltk_event){.button = { + .type = LTK_BUTTONRELEASE_EVENT, + .button = get_button(xevent.xbutton.button), + .x = xevent.xbutton.x, + .y = xevent.xbutton.y + }}; + break; + case MotionNotify: + *event = (ltk_event){.motion = { + .type = LTK_MOTION_EVENT, + .x = xevent.xmotion.x, + .y = xevent.xmotion.y + }}; + break; + case ConfigureNotify: + *event = (ltk_event){.configure = { + .type = LTK_CONFIGURE_EVENT, + .x = xevent.xconfigure.x, + .y = xevent.xconfigure.y, + .w = xevent.xconfigure.width, + .h = xevent.xconfigure.height + }}; + break; + case Expose: + /* FIXME: ignoring all of these events would make it not + work anymore if the actual rectangle wasn't ignored + later anyways */ + if (xevent.xexpose.count == 0) { + *event = (ltk_event){.expose = { + .type = LTK_EXPOSE_EVENT, + .x = xevent.xexpose.x, + .y = xevent.xexpose.y, + .w = xevent.xexpose.width, + .h = xevent.xexpose.height + }}; + } + break; + case ClientMessage: + if ((Atom)xevent.xclient.data.l[0] == renderdata->wm_delete_msg) + *event = (ltk_event){.type = LTK_WINDOWCLOSE_EVENT}; + break; + } +} diff --git a/src/graphics.h b/src/graphics.h @@ -14,12 +14,14 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef _LTK_GRAPHICS_H_ -#define _LTK_GRAPHICS_H_ +#ifndef LTK_GRAPHICS_H +#define LTK_GRAPHICS_H /* FIXME: make this global and use it elsewhere */ #define USE_XLIB_GRAPHICS 1 +typedef struct ltk_renderdata ltk_renderdata; + /* FIXME: Is it faster to take ltk_color* or ltk_color? */ #include <X11/Xft/Xft.h> @@ -45,13 +47,13 @@ typedef struct { /* typedef struct ltk_surface ltk_surface; */ /* FIXME: graphics context */ -ltk_surface *ltk_surface_create(ltk_window *window, int w, int h); +ltk_surface *ltk_surface_create(ltk_renderdata *renderdata, int w, int h); void ltk_surface_destroy(ltk_surface *s); /* returns 0 if successful, 1 if not resizable */ int ltk_surface_resize(ltk_surface *s, int w, int h); /* FIXME: kind of hacky */ void ltk_surface_update_size(ltk_surface *s, int w, int h); -ltk_surface *ltk_surface_from_window(ltk_window *window); +ltk_surface *ltk_surface_from_window(ltk_renderdata *renderdata, int w, int h); void ltk_surface_get_size(ltk_surface *s, int *w, int *h); void ltk_surface_copy(ltk_surface *src, ltk_surface *dst, ltk_rect src_rect, int dst_x, int dst_y); void ltk_surface_draw_rect(ltk_surface *s, ltk_color *c, ltk_rect rect, int line_width); @@ -76,4 +78,12 @@ XftDraw *ltk_surface_get_xft_draw(ltk_surface *s); Drawable ltk_surface_get_drawable(ltk_surface *s); #endif -#endif /* _LTK_GRAPHICS_H_ */ +ltk_renderdata *renderer_create_window(const char *title, int x, int y, unsigned int w, unsigned int h); +void renderer_destroy_window(ltk_renderdata *renderdata); +void renderer_set_window_properties(ltk_renderdata *renderdata, ltk_color *bg, ltk_color *border, unsigned int border_width); +/* FIXME: this is kind of out of place */ +void renderer_swap_buffers(ltk_renderdata *renderdata); +/* FIXME: this is just for the socket name and is a bit weird */ +unsigned long renderer_get_window_id(ltk_renderdata *renderdata); + +#endif /* LTK_GRAPHICS_H */ diff --git a/src/graphics_xlib.c b/src/graphics_xlib.c @@ -16,18 +16,19 @@ #include <X11/Xlib.h> #include <X11/Xutil.h> +#include <X11/extensions/Xdbe.h> #include <stdint.h> #include "color.h" #include "rect.h" -#include "widget.h" -#include "ltk.h" +#include "util.h" #include "memory.h" #include "compat.h" +#include "xlib_shared.h" struct ltk_surface { int w, h; - ltk_window *window; + ltk_renderdata *renderdata; Drawable d; #if USE_XFT == 1 XftDraw *xftdraw; @@ -36,7 +37,7 @@ struct ltk_surface { }; ltk_surface * -ltk_surface_create(ltk_window *window, int w, int h) { +ltk_surface_create(ltk_renderdata *renderdata, int w, int h) { ltk_surface *s = ltk_malloc(sizeof(ltk_surface)); if (w <= 0) w = 1; @@ -44,24 +45,24 @@ ltk_surface_create(ltk_window *window, int w, int h) { h = 1; s->w = w; s->h = h; - s->window = window; - s->d = XCreatePixmap(window->dpy, window->xwindow, w, h, window->depth); + s->renderdata = renderdata; + s->d = XCreatePixmap(renderdata->dpy, renderdata->xwindow, w, h, renderdata->depth); #if USE_XFT == 1 - s->xftdraw = XftDrawCreate(window->dpy, s->d, window->vis, window->cm); + s->xftdraw = XftDrawCreate(renderdata->dpy, s->d, renderdata->vis, renderdata->cm); #endif s->resizable = 1; return s; } ltk_surface * -ltk_surface_from_window(ltk_window *window) { +ltk_surface_from_window(ltk_renderdata *renderdata, int w, int h) { ltk_surface *s = ltk_malloc(sizeof(ltk_surface)); - s->w = window->rect.w; - s->h = window->rect.h; - s->window = window; - s->d = window->drawable; + s->w = w; + s->h = h; + s->renderdata = renderdata; + s->d = renderdata->drawable; #if USE_XFT == 1 - s->xftdraw = XftDrawCreate(window->dpy, s->d, window->vis, window->cm); + s->xftdraw = XftDrawCreate(renderdata->dpy, s->d, renderdata->vis, renderdata->cm); #endif s->resizable = 0; return s; @@ -73,12 +74,13 @@ ltk_surface_destroy(ltk_surface *s) { XftDrawDestroy(s->xftdraw); #endif if (s->resizable) - XFreePixmap(s->window->dpy, (Pixmap)s->d); + XFreePixmap(s->renderdata->dpy, (Pixmap)s->d); ltk_free(s); } void ltk_surface_update_size(ltk_surface *s, int w, int h) { + /* FIXME: maybe return directly if surface is resizable? */ s->w = w; s->h = h; } @@ -89,8 +91,8 @@ ltk_surface_resize(ltk_surface *s, int w, int h) { return 1; s->w = w; s->h = h; - XFreePixmap(s->window->dpy, (Pixmap)s->d); - s->d = XCreatePixmap(s->window->dpy, s->window->xwindow, w, h, s->window->depth); + XFreePixmap(s->renderdata->dpy, (Pixmap)s->d); + s->d = XCreatePixmap(s->renderdata->dpy, s->renderdata->xwindow, w, h, s->renderdata->depth); #if USE_XFT == 1 XftDrawChange(s->xftdraw, s->d); #endif @@ -105,30 +107,30 @@ ltk_surface_get_size(ltk_surface *s, int *w, int *h) { void ltk_surface_draw_rect(ltk_surface *s, ltk_color *c, ltk_rect rect, int line_width) { - XSetForeground(s->window->dpy, s->window->gc, c->xcolor.pixel); - XSetLineAttributes(s->window->dpy, s->window->gc, line_width, LineSolid, CapButt, JoinMiter); - XDrawRectangle(s->window->dpy, s->d, s->window->gc, rect.x, rect.y, rect.w, rect.h); + XSetForeground(s->renderdata->dpy, s->renderdata->gc, c->xcolor.pixel); + XSetLineAttributes(s->renderdata->dpy, s->renderdata->gc, line_width, LineSolid, CapButt, JoinMiter); + XDrawRectangle(s->renderdata->dpy, s->d, s->renderdata->gc, rect.x, rect.y, rect.w, rect.h); } void ltk_surface_draw_border(ltk_surface *s, ltk_color *c, ltk_rect rect, int line_width, ltk_border_sides border_sides) { /* drawn as rectangles to have proper control over line width - I'm not sure how exactly XDrawLine handles even line widths (i.e. on which side the extra pixel will be) */ - XSetForeground(s->window->dpy, s->window->gc, c->xcolor.pixel); + XSetForeground(s->renderdata->dpy, s->renderdata->gc, c->xcolor.pixel); if (border_sides & LTK_BORDER_TOP) - XFillRectangle(s->window->dpy, s->d, s->window->gc, rect.x, rect.y, rect.w, line_width); + XFillRectangle(s->renderdata->dpy, s->d, s->renderdata->gc, rect.x, rect.y, rect.w, line_width); if (border_sides & LTK_BORDER_BOTTOM) - XFillRectangle(s->window->dpy, s->d, s->window->gc, rect.x, rect.y + rect.h - line_width, rect.w, line_width); + XFillRectangle(s->renderdata->dpy, s->d, s->renderdata->gc, rect.x, rect.y + rect.h - line_width, rect.w, line_width); if (border_sides & LTK_BORDER_LEFT) - XFillRectangle(s->window->dpy, s->d, s->window->gc, rect.x, rect.y, line_width, rect.h); + XFillRectangle(s->renderdata->dpy, s->d, s->renderdata->gc, rect.x, rect.y, line_width, rect.h); if (border_sides & LTK_BORDER_RIGHT) - XFillRectangle(s->window->dpy, s->d, s->window->gc, rect.x + rect.w - line_width, rect.y, line_width, rect.h); + XFillRectangle(s->renderdata->dpy, s->d, s->renderdata->gc, rect.x + rect.w - line_width, rect.y, line_width, rect.h); } void ltk_surface_fill_rect(ltk_surface *s, ltk_color *c, ltk_rect rect) { - XSetForeground(s->window->dpy, s->window->gc, c->xcolor.pixel); - XFillRectangle(s->window->dpy, s->d, s->window->gc, rect.x, rect.y, rect.w, rect.h); + XSetForeground(s->renderdata->dpy, s->renderdata->gc, c->xcolor.pixel); + XFillRectangle(s->renderdata->dpy, s->d, s->renderdata->gc, rect.x, rect.y, rect.w, rect.h); } void @@ -147,8 +149,8 @@ ltk_surface_fill_polygon(ltk_surface *s, ltk_color *c, ltk_point *points, size_t final_points[i].x = (short)points[i].x; final_points[i].y = (short)points[i].y; } - XSetForeground(s->window->dpy, s->window->gc, c->xcolor.pixel); - XFillPolygon(s->window->dpy, s->d, s->window->gc, final_points, (int)npoints, Complex, CoordModeOrigin); + XSetForeground(s->renderdata->dpy, s->renderdata->gc, c->xcolor.pixel); + XFillPolygon(s->renderdata->dpy, s->d, s->renderdata->gc, final_points, (int)npoints, Complex, CoordModeOrigin); if (npoints > 6) free(final_points); } @@ -156,7 +158,7 @@ ltk_surface_fill_polygon(ltk_surface *s, ltk_color *c, ltk_point *points, size_t void ltk_surface_copy(ltk_surface *src, ltk_surface *dst, ltk_rect src_rect, int dst_x, int dst_y) { XCopyArea( - src->window->dpy, src->d, dst->d, src->window->gc, + src->renderdata->dpy, src->d, dst->d, src->renderdata->gc, src_rect.x, src_rect.y, src_rect.w, src_rect.h, dst_x, dst_y ); } @@ -187,9 +189,124 @@ ltk_surface_get_xft_draw(ltk_surface *s) { } #endif -#if USE_XLIB_GRAPHICS == 1 Drawable ltk_surface_get_drawable(ltk_surface *s) { return s->d; } -#endif + +ltk_renderdata * +renderer_create_window(const char *title, int x, int y, unsigned int w, unsigned int h) { + XSetWindowAttributes attrs; + ltk_renderdata *renderdata = ltk_malloc(sizeof(ltk_renderdata)); + + renderdata->dpy = XOpenDisplay(NULL); + renderdata->screen = DefaultScreen(renderdata->dpy); + /* based on http://wili.cc/blog/xdbe.html */ + int major, minor, found = 0; + if (XdbeQueryExtension(renderdata->dpy, &major, &minor)) { + int num_screens = 1; + Drawable screens[] = {DefaultRootWindow(renderdata->dpy)}; + XdbeScreenVisualInfo *info = XdbeGetVisualInfo( + renderdata->dpy, screens, &num_screens + ); + if (!info || num_screens < 1 || info->count < 1) { + ltk_fatal("No visuals support Xdbe."); + } + XVisualInfo xvisinfo_templ; + /* we know there's at least one */ + xvisinfo_templ.visualid = info->visinfo[0].visual; + /* FIXME: proper screen number? */ + xvisinfo_templ.screen = 0; + xvisinfo_templ.depth = info->visinfo[0].depth; + int matches; + XVisualInfo *xvisinfo_match = XGetVisualInfo( + renderdata->dpy, + VisualIDMask | VisualScreenMask | VisualDepthMask, + &xvisinfo_templ, &matches + ); + if (!xvisinfo_match || matches < 1) { + ltk_fatal("Couldn't match a Visual with double buffering.\n"); + } + renderdata->vis = xvisinfo_match->visual; + /* FIXME: is it legal to free this while keeping the visual? */ + XFree(xvisinfo_match); + XdbeFreeVisualInfo(info); + found = 1; + } else { + renderdata->vis = DefaultVisual(renderdata->dpy, renderdata->screen); + ltk_warn("No Xdbe support.\n"); + } + renderdata->cm = DefaultColormap(renderdata->dpy, renderdata->screen); + renderdata->wm_delete_msg = XInternAtom(renderdata->dpy, "WM_DELETE_WINDOW", False); + + memset(&attrs, 0, sizeof(attrs)); + attrs.background_pixel = BlackPixel(renderdata->dpy, renderdata->screen); + attrs.colormap = renderdata->cm; + attrs.border_pixel = WhitePixel(renderdata->dpy, renderdata->screen); + /* this causes the window contents to be kept + * when it is resized, leading to less flicker */ + attrs.bit_gravity = NorthWestGravity; + attrs.event_mask = + ExposureMask | KeyPressMask | KeyReleaseMask | + ButtonPressMask | ButtonReleaseMask | + StructureNotifyMask | PointerMotionMask; + renderdata->depth = DefaultDepth(renderdata->dpy, renderdata->screen); + /* FIXME: set border width */ + renderdata->xwindow = XCreateWindow( + renderdata->dpy, DefaultRootWindow(renderdata->dpy), x, y, + w, h, 0, renderdata->depth, + InputOutput, renderdata->vis, + CWBackPixel | CWColormap | CWBitGravity | CWEventMask | CWBorderPixel, &attrs + ); + + if (found) { + renderdata->back_buf = XdbeAllocateBackBufferName( + renderdata->dpy, renderdata->xwindow, XdbeBackground + ); + } else { + renderdata->back_buf = renderdata->xwindow; + } + renderdata->drawable = renderdata->back_buf; + renderdata->gc = XCreateGC(renderdata->dpy, renderdata->xwindow, 0, 0); + XSetStandardProperties( + renderdata->dpy, renderdata->xwindow, + title, NULL, None, NULL, 0, NULL + ); + XSetWMProtocols(renderdata->dpy, renderdata->xwindow, &renderdata->wm_delete_msg, 1); + XClearWindow(renderdata->dpy, renderdata->xwindow); + XMapRaised(renderdata->dpy, renderdata->xwindow); + + return renderdata; +} + +void +renderer_destroy_window(ltk_renderdata *renderdata) { + XFreeGC(renderdata->dpy, renderdata->gc); + XDestroyWindow(renderdata->dpy, renderdata->xwindow); + XCloseDisplay(renderdata->dpy); + free(renderdata); +} + +/* FIXME: this is a completely random collection of properties and should be + changed to a more sensible list */ +void +renderer_set_window_properties(ltk_renderdata *renderdata, ltk_color *bg, ltk_color *border, unsigned int border_width) { + XSetWindowBorder(renderdata->dpy, renderdata->xwindow, border->xcolor.pixel); + XSetWindowBackground(renderdata->dpy, renderdata->xwindow, bg->xcolor.pixel); + XSetWindowBorderWidth(renderdata->dpy, renderdata->xwindow, border_width); +} + +void +renderer_swap_buffers(ltk_renderdata *renderdata) { + XdbeSwapInfo swap_info; + swap_info.swap_window = renderdata->xwindow; + swap_info.swap_action = XdbeBackground; + if (!XdbeSwapBuffers(renderdata->dpy, &swap_info, 1)) + ltk_fatal("Unable to swap buffers.\n"); + XFlush(renderdata->dpy); +} + +unsigned long +renderer_get_window_id(ltk_renderdata *renderdata) { + return (unsigned long)renderdata->xwindow; +} diff --git a/src/grid.c b/src/grid.c @@ -28,9 +28,7 @@ #include <stdarg.h> #include <stdint.h> -#include <X11/Xlib.h> -#include <X11/Xutil.h> - +#include "event.h" #include "memory.h" #include "color.h" #include "rect.h" @@ -52,9 +50,9 @@ static int ltk_grid_add(ltk_window *window, ltk_widget *widget, ltk_grid *grid, static int ltk_grid_ungrid(ltk_window *window, ltk_widget *widget, ltk_widget *self, char **errstr); static int ltk_grid_find_nearest_column(ltk_grid *grid, int x); static int ltk_grid_find_nearest_row(ltk_grid *grid, int y); -static int ltk_grid_mouse_press(ltk_widget *self, XEvent event); -static int ltk_grid_mouse_release(ltk_widget *self, XEvent event); -static int ltk_grid_motion_notify(ltk_widget *self, XEvent event); +static int ltk_grid_mouse_press(ltk_widget *self, ltk_event *event); +static int ltk_grid_mouse_release(ltk_widget *self, ltk_event *event); +static int ltk_grid_motion_notify(ltk_widget *self, ltk_event *event); static struct ltk_widget_vtable vtable = { .draw = &ltk_grid_draw, @@ -386,10 +384,10 @@ ltk_grid_find_nearest_row(ltk_grid *grid, int y) { } static int -ltk_grid_mouse_press(ltk_widget *self, XEvent event) { +ltk_grid_mouse_press(ltk_widget *self, ltk_event *event) { ltk_grid *grid = (ltk_grid *)self; - int x = event.xbutton.x; - int y = event.xbutton.y; + int x = event->button.x; + int y = event->button.y; int row = ltk_grid_find_nearest_row(grid, y); int column = ltk_grid_find_nearest_column(grid, x); if (row == -1 || column == -1) @@ -403,10 +401,10 @@ ltk_grid_mouse_press(ltk_widget *self, XEvent event) { } static int -ltk_grid_mouse_release(ltk_widget *self, XEvent event) { +ltk_grid_mouse_release(ltk_widget *self, ltk_event *event) { ltk_grid *grid = (ltk_grid *)self; - int x = event.xbutton.x; - int y = event.xbutton.y; + int x = event->button.x; + int y = event->button.y; int row = ltk_grid_find_nearest_row(grid, y); int column = ltk_grid_find_nearest_column(grid, x); if (row == -1 || column == -1) @@ -420,14 +418,10 @@ ltk_grid_mouse_release(ltk_widget *self, XEvent event) { } static int -ltk_grid_motion_notify(ltk_widget *self, XEvent event) { +ltk_grid_motion_notify(ltk_widget *self, ltk_event *event) { ltk_grid *grid = (ltk_grid *)self; - /* FIXME: Why does it check this? */ - short pressed = (event.xmotion.state & Button1Mask) == Button1Mask; - if (pressed) - return 0; - int x = event.xbutton.x; - int y = event.xbutton.y; + int x = event->motion.x; + int y = event->motion.y; int row = ltk_grid_find_nearest_row(grid, y); int column = ltk_grid_find_nearest_column(grid, x); if (row == -1 || column == -1) diff --git a/src/label.c b/src/label.c @@ -20,9 +20,7 @@ #include <string.h> #include <stdarg.h> -#include <X11/Xlib.h> -#include <X11/Xutil.h> - +#include "event.h" #include "memory.h" #include "color.h" #include "rect.h" diff --git a/src/ltk.h b/src/ltk.h @@ -17,29 +17,17 @@ #ifndef _LTK_H_ #define _LTK_H_ -#include <X11/Xlib.h> -#include <X11/Xutil.h> #include <stdint.h> -#include <X11/extensions/Xdbe.h> -#include "color.h" typedef enum { LTK_EVENT_RESIZE = 1 << 0, LTK_EVENT_BUTTON = 1 << 1, LTK_EVENT_KEY = 1 << 2, LTK_EVENT_MENU = 1 << 3 -} ltk_event_type; - -typedef struct { - int border_width; - int font_size; - char *font; - ltk_color fg; - ltk_color bg; -} ltk_window_theme; +} ltk_userevent_type; struct ltk_event_queue { - ltk_event_type event_type; + ltk_userevent_type event_type; char *data; struct ltk_event_queue *prev; struct ltk_event_queue *next; @@ -59,28 +47,21 @@ struct ltk_event_queue { typedef struct ltk_window ltk_window; typedef struct ltk_text_context ltk_text_context; typedef struct ltk_surface ltk_surface; +typedef struct ltk_window_theme ltk_window_theme; #include "widget.h" #include "surface_cache.h" +#include "event.h" struct ltk_window { - Display *dpy; - Visual *vis; + ltk_renderdata *renderdata; ltk_surface_cache *surface_cache; ltk_text_context *text_context; ltk_surface *surface; - Colormap cm; - GC gc; - int screen; - Atom wm_delete_msg; - Window xwindow; - XdbeBackBuffer back_buf; - Drawable drawable; - int depth; ltk_widget *root_widget; ltk_widget *active_widget; ltk_widget *pressed_widget; - void (*other_event) (struct ltk_window *, XEvent event); + void (*other_event) (struct ltk_window *, ltk_event *event); ltk_rect rect; ltk_window_theme *theme; ltk_rect dirty_rect; @@ -96,9 +77,18 @@ struct ltk_window { char popups_locked; }; +#include "color.h" + +struct ltk_window_theme { + int border_width; + int font_size; + char *font; + ltk_color fg; + ltk_color bg; +}; + void ltk_window_invalidate_rect(ltk_window *window, ltk_rect rect); -int ltk_create_xcolor(ltk_window *window, const char *hex, XColor *col); -void ltk_queue_event(ltk_window *window, ltk_event_type type, const char *id, const char *data); +void ltk_queue_event(ltk_window *window, ltk_userevent_type type, const char *id, const char *data); void ltk_window_set_active_widget(ltk_window *window, ltk_widget *widget); void ltk_window_set_pressed_widget(ltk_window *window, ltk_widget *widget); void ltk_quit(ltk_window *window); diff --git a/src/ltkd.c b/src/ltkd.c @@ -36,12 +36,11 @@ #include <sys/select.h> #include <sys/socket.h> -#include <X11/Xlib.h> -#include <X11/Xutil.h> - #include "ini.h" #include "khash.h" +#include "graphics.h" +#include "surface_cache.h" #include "theme.h" #include "memory.h" #include "color.h" @@ -113,8 +112,8 @@ static ltk_window *ltk_create_window(const char *title, int x, int y, unsigned int w, unsigned int h); static void ltk_destroy_window(ltk_window *window); static void ltk_redraw_window(ltk_window *window); -static void ltk_window_other_event(ltk_window *window, XEvent event); -static void ltk_handle_event(ltk_window *window, XEvent event); +static void ltk_window_other_event(ltk_window *window, ltk_event *event); +static void ltk_handle_event(ltk_window *window, ltk_event *event); static void ltk_load_theme(ltk_window *window, const char *path); static void ltk_uninitialize_theme(ltk_window *window); @@ -172,7 +171,7 @@ int main(int argc, char *argv[]) { anyways, so it doesn't matter, but still... */ main_window = ltk_create_window(title, 0, 0, 500, 500); - sock_path = get_sock_path(ltk_dir, main_window->xwindow); + sock_path = get_sock_path(ltk_dir, renderer_get_window_id(main_window->renderdata)); if (!sock_path) ltk_fatal_errno("Unable to allocate memory for socket path.\n"); /* Note: sockets should be initialized to 0 because it is static */ @@ -189,7 +188,7 @@ int main(int argc, char *argv[]) { static int ltk_mainloop(ltk_window *window) { - XEvent event; + ltk_event event; fd_set rfds, wfds, rallfds, wallfds; int maxfd; int rretval, wretval; @@ -207,7 +206,7 @@ ltk_mainloop(ltk_window *window) { FD_SET(listenfd, &rallfds); maxfd = listenfd; - printf("%lu", window->xwindow); + printf("%lu", renderer_get_window_id(main_window->renderdata)); fflush(stdout); if (daemonize_flag) daemonize(); @@ -218,6 +217,8 @@ ltk_mainloop(ltk_window *window) { struct timespec now, elapsed, last; clock_gettime(CLOCK_MONOTONIC, &last); + /* FIXME: framerate limiting for draw */ + while (running) { rfds = rallfds; wfds = wallfds; @@ -228,9 +229,9 @@ ltk_mainloop(ltk_window *window) { /* value of tv doesn't really matter anymore here because the necessary framerate-limiting delay is already done */ wretval = select(maxfd + 1, NULL, &wfds, NULL, &tv); - while (XPending(window->dpy)) { - XNextEvent(window->dpy, &event); - ltk_handle_event(window, event); + while (ltk_events_pending(window->renderdata)) { + ltk_next_event(window->renderdata, &event); + ltk_handle_event(window, &event); } if (rretval > 0 || (sock_write_available && wretval > 0)) { @@ -459,7 +460,7 @@ ltk_log_msg(const char *mode, const char *format, va_list args) { strftime(logtime, 25, "%Y-%m-%d %H:%M:%S", timeptr); if (main_window) - fprintf(stderr, "%s ltkd(%lu) %s: ", logtime, main_window->xwindow, mode); + fprintf(stderr, "%s ltkd(%lu) %s: ", logtime, renderer_get_window_id(main_window->renderdata), mode); else fprintf(stderr, "%s ltkd(?) %s: ", logtime, mode); vfprintf(stderr, format, args); @@ -495,18 +496,8 @@ ltk_window_invalidate_rect(ltk_window *window, ltk_rect rect) { window->dirty_rect = ltk_rect_union(rect, window->dirty_rect); } -/* FIXME: Proper error checking by calling functions */ -int -ltk_create_xcolor(ltk_window *window, const char *hex, XColor *col) { - if (!XParseColor(window->dpy, window->cm, hex, col)) - return 0; - XAllocColor(window->dpy, window->cm, col); - - return 1; -} - void -ltk_queue_event(ltk_window *window, ltk_event_type type, const char *id, const char *data) { +ltk_queue_event(ltk_window *window, ltk_userevent_type type, const char *id, const char *data) { /* FIXME: make it nicer and safer */ struct ltk_event_queue *new = ltk_malloc(sizeof(struct ltk_event_queue)); new->event_type = type; @@ -535,14 +526,9 @@ ltk_redraw_window(ltk_window *window) { window->dirty_rect.w -= window->dirty_rect.x + window->dirty_rect.w - window->rect.w; if (window->dirty_rect.y + window->dirty_rect.h > window->rect.h) window->dirty_rect.h -= window->dirty_rect.y + window->dirty_rect.h - window->rect.h; - XSetForeground(window->dpy, window->gc, window->theme->bg.xcolor.pixel); /* FIXME: this should use window->dirty_rect, but that doesn't work properly with double buffering */ - XFillRectangle( - window->dpy, window->drawable, window->gc, - window->rect.x, window->rect.y, - window->rect.w, window->rect.h - ); + ltk_surface_fill_rect(window->surface, &window->theme->bg, (ltk_rect){0, 0, window->rect.w, window->rect.h}); if (window->root_widget) { ptr = window->root_widget; ptr->vtable->draw(ptr, window->rect); @@ -552,22 +538,17 @@ ltk_redraw_window(ltk_window *window) { ptr = window->popups[i]; ptr->vtable->draw(ptr, window->rect); } - XdbeSwapInfo swap_info; - swap_info.swap_window = window->xwindow; - swap_info.swap_action = XdbeBackground; - if (!XdbeSwapBuffers(window->dpy, &swap_info, 1)) - ltk_fatal("Unable to swap buffers.\n"); - XFlush(window->dpy); + renderer_swap_buffers(window->renderdata); } static void -ltk_window_other_event(ltk_window *window, XEvent event) { +ltk_window_other_event(ltk_window *window, ltk_event *event) { ltk_widget *ptr = window->root_widget; - if (event.type == ConfigureNotify) { + if (event->type == LTK_CONFIGURE_EVENT) { ltk_window_unregister_all_popups(window); int w, h; - w = event.xconfigure.width; - h = event.xconfigure.height; + w = event->configure.w; + h = event->configure.h; int orig_w = window->rect.w; int orig_h = window->rect.h; if (orig_w != w || orig_h != h) { @@ -581,15 +562,14 @@ ltk_window_other_event(ltk_window *window, XEvent event) { ltk_widget_resize(ptr); } } - } else if (event.type == Expose && event.xexpose.count == 0) { + } else if (event->type == LTK_EXPOSE_EVENT) { ltk_rect r; - r.x = event.xexpose.x; - r.y = event.xexpose.y; - r.w = event.xexpose.width; - r.h = event.xexpose.height; + r.x = event->expose.x; + r.y = event->expose.y; + r.w = event->expose.w; + r.h = event->expose.h; ltk_window_invalidate_rect(window, r); - } else if (event.type == ClientMessage - && (Atom)event.xclient.data.l[0] == window->wm_delete_msg) { + } else if (event->type == LTK_WINDOWCLOSE_EVENT) { ltk_quit(window); } } @@ -784,7 +764,6 @@ ltk_uninitialize_theme(ltk_window *window) { static ltk_window * ltk_create_window(const char *title, int x, int y, unsigned int w, unsigned int h) { char *theme_path; - XSetWindowAttributes attrs; ltk_window *window = ltk_malloc(sizeof(ltk_window)); @@ -792,111 +771,39 @@ ltk_create_window(const char *title, int x, int y, unsigned int w, unsigned int window->popups_num = window->popups_alloc = 0; window->popups_locked = 0; - window->dpy = XOpenDisplay(NULL); - window->screen = DefaultScreen(window->dpy); - /* based on http://wili.cc/blog/xdbe.html */ - int major, minor, found = 0; - if (XdbeQueryExtension(window->dpy, &major, &minor)) { - int num_screens = 1; - Drawable screens[] = {DefaultRootWindow(window->dpy)}; - XdbeScreenVisualInfo *info = XdbeGetVisualInfo( - window->dpy, screens, &num_screens - ); - if (!info || num_screens < 1 || info->count < 1) { - ltk_fatal("No visuals support Xdbe."); - } - XVisualInfo xvisinfo_templ; - /* we know there's at least one */ - xvisinfo_templ.visualid = info->visinfo[0].visual; - /* FIXME: proper screen number? */ - xvisinfo_templ.screen = 0; - xvisinfo_templ.depth = info->visinfo[0].depth; - int matches; - XVisualInfo *xvisinfo_match = XGetVisualInfo( - window->dpy, - VisualIDMask | VisualScreenMask | VisualDepthMask, - &xvisinfo_templ, &matches - ); - if (!xvisinfo_match || matches < 1) { - ltk_fatal("Couldn't match a Visual with double buffering.\n"); - } - window->vis = xvisinfo_match->visual; - /* FIXME: is it legal to free this while keeping the visual? */ - XFree(xvisinfo_match); - XdbeFreeVisualInfo(info); - found = 1; - } else { - window->vis = DefaultVisual(window->dpy, window->screen); - ltk_warn("No Xdbe support.\n"); - } - //printf("%d %d\n", WidthOfScreen(XDefaultScreenOfDisplay(window->dpy)), WidthMMOfScreen(XDefaultScreenOfDisplay(window->dpy))); - window->cm = DefaultColormap(window->dpy, window->screen); + ltk_renderdata *renderer_create_window(const char *title, int x, int y, unsigned int w, unsigned int h); + void renderer_set_window_properties(ltk_renderdata *renderdata, ltk_color *bg_pixel, ltk_color *border_pixel, unsigned int border_width); + window->renderdata = renderer_create_window(title, x, y, w, h); theme_path = ltk_strcat_useful(ltk_dir, "/theme.ini"); window->theme = &window_theme; ltk_load_theme(window, theme_path); ltk_free(theme_path); + /* FIXME: fix theme memory leaks when exit happens between here and the end of this function */ - window->wm_delete_msg = XInternAtom(window->dpy, "WM_DELETE_WINDOW", False); - - memset(&attrs, 0, sizeof(attrs)); - attrs.background_pixel = window->theme->bg.xcolor.pixel; - attrs.colormap = window->cm; - attrs.border_pixel = window->theme->fg.xcolor.pixel; - /* this causes the window contents to be kept - * when it is resized, leading to less flicker */ - attrs.bit_gravity = NorthWestGravity; - attrs.event_mask = - ExposureMask | KeyPressMask | KeyReleaseMask | - ButtonPressMask | ButtonReleaseMask | - StructureNotifyMask | PointerMotionMask; - window->depth = DefaultDepth(window->dpy, window->screen); - window->xwindow = XCreateWindow( - window->dpy, DefaultRootWindow(window->dpy), x, y, - w, h, window->theme->border_width, window->depth, - InputOutput, window->vis, - CWBackPixel | CWColormap | CWBitGravity | CWEventMask | CWBorderPixel, &attrs - ); - - if (found) { - window->back_buf = XdbeAllocateBackBufferName( - window->dpy, window->xwindow, XdbeBackground - ); - } else { - window->back_buf = window->xwindow; - } - window->drawable = window->back_buf; - window->gc = XCreateGC(window->dpy, window->xwindow, 0, 0); - XSetForeground(window->dpy, window->gc, window->theme->fg.xcolor.pixel); - XSetBackground(window->dpy, window->gc, window->theme->bg.xcolor.pixel); - XSetStandardProperties( - window->dpy, window->xwindow, - title, NULL, None, NULL, 0, NULL - ); - XSetWMProtocols(window->dpy, window->xwindow, &window->wm_delete_msg, 1); + + renderer_set_window_properties(window->renderdata, &window->theme->bg, &window->theme->fg, window->theme->border_width); + window->root_widget = NULL; window->active_widget = NULL; window->pressed_widget = NULL; - window->surface_cache = ltk_surface_cache_create(window); + window->surface_cache = ltk_surface_cache_create(window->renderdata); window->other_event = &ltk_window_other_event; window->first_event = window->last_event = NULL; - window->rect.w = 0; - window->rect.h = 0; + window->rect.w = w; + window->rect.h = h; window->rect.x = 0; window->rect.y = 0; window->dirty_rect.w = 0; window->dirty_rect.h = 0; window->dirty_rect.x = 0; window->dirty_rect.y = 0; - window->surface = ltk_surface_from_window(window); + window->surface = ltk_surface_from_window(window->renderdata, w, h); window->text_context = ltk_text_context_create(window, window->theme->font); - XClearWindow(window->dpy, window->xwindow); - XMapRaised(window->dpy, window->xwindow); - return window; } @@ -905,11 +812,9 @@ ltk_destroy_window(ltk_window *window) { ltk_text_context_destroy(window->text_context); if (window->popups) ltk_free(window->popups); - XFreeGC(window->dpy, window->gc); - XDestroyWindow(window->dpy, window->xwindow); - XCloseDisplay(window->dpy); - ltk_surface_destroy(window->surface); ltk_surface_cache_destroy(window->surface_cache); + ltk_surface_destroy(window->surface); + renderer_destroy_window(window->renderdata); ltk_free(window); } @@ -958,16 +863,16 @@ get_hover_popup(ltk_window *window, int x, int y) { } static void -ltk_handle_event(ltk_window *window, XEvent event) { +ltk_handle_event(ltk_window *window, ltk_event *event) { ltk_widget *hover_popup; ltk_widget *root_widget = window->root_widget; - switch (event.type) { - case KeyPress: + switch (event->type) { + case LTK_KEYPRESS_EVENT: break; - case KeyRelease: + case LTK_KEYRELEASE_EVENT: break; - case ButtonPress: - hover_popup = get_hover_popup(window, event.xbutton.x, event.xbutton.y); + case LTK_BUTTONPRESS_EVENT: + hover_popup = get_hover_popup(window, event->button.x, event->button.y); if (hover_popup) { ltk_widget_mouse_press_event(hover_popup, event); } else if (root_widget) { @@ -975,15 +880,15 @@ ltk_handle_event(ltk_window *window, XEvent event) { ltk_widget_mouse_press_event(root_widget, event); } break; - case ButtonRelease: - hover_popup = get_hover_popup(window, event.xbutton.x, event.xbutton.y); + case LTK_BUTTONRELEASE_EVENT: + hover_popup = get_hover_popup(window, event->button.x, event->button.y); if (hover_popup) ltk_widget_mouse_release_event(hover_popup, event); else if (root_widget) ltk_widget_mouse_release_event(root_widget, event); break; - case MotionNotify: - hover_popup = get_hover_popup(window, event.xmotion.x, event.xmotion.y); + case LTK_MOTION_EVENT: + hover_popup = get_hover_popup(window, event->motion.x, event->motion.y); if (hover_popup) ltk_widget_motion_notify_event(hover_popup, event); else if (root_widget) diff --git a/src/memory.c b/src/memory.c @@ -16,12 +16,9 @@ #include <stdio.h> #include <stdlib.h> -#include <X11/Xlib.h> -#include <X11/Xutil.h> #include <stdarg.h> #include <string.h> #include <stdint.h> -#include "color.h" #include "util.h" #include "memory.h" diff --git a/src/menu.c b/src/menu.c @@ -21,9 +21,7 @@ #include <stdarg.h> #include <math.h> -#include <X11/Xlib.h> -#include <X11/Xutil.h> - +#include "event.h" #include "memory.h" #include "color.h" #include "rect.h" @@ -88,15 +86,15 @@ static void ltk_menu_scroll_callback(void *data); static void stop_scrolling(ltk_menu *menu); static size_t get_entry_at_point(ltk_menu *menu, int x, int y, ltk_rect *entry_rect_ret); static int set_scroll_timer(ltk_menu *menu, int x, int y); -static int ltk_menu_mouse_release(ltk_widget *self, XEvent event); -static int ltk_menu_mouse_press(ltk_widget *self, XEvent event); +static int ltk_menu_mouse_release(ltk_widget *self, ltk_event *event); +static int ltk_menu_mouse_press(ltk_widget *self, ltk_event *event); static void ltk_menu_hide(ltk_widget *self); static void popup_active_menu(ltk_menu *menu, ltk_rect r); static void unpopup_active_entry(ltk_menu *menu); static void handle_hover(ltk_menu *menu, int x, int y); -static int ltk_menu_motion_notify(ltk_widget *self, XEvent event); -static int ltk_menu_mouse_enter(ltk_widget *self, XEvent event); -static int ltk_menu_mouse_leave(ltk_widget *self, XEvent event); +static int ltk_menu_motion_notify(ltk_widget *self, ltk_event *event); +static int ltk_menu_mouse_enter(ltk_widget *self, ltk_event *event); +static int ltk_menu_mouse_leave(ltk_widget *self, ltk_event *event); static ltk_menu *ltk_menu_create(ltk_window *window, const char *id, int is_submenu); static ltk_menuentry *insert_entry(ltk_menu *menu, size_t idx); static void recalc_menu_size(ltk_menu *menu); @@ -604,9 +602,9 @@ set_scroll_timer(ltk_menu *menu, int x, int y) { } static int -ltk_menu_mouse_release(ltk_widget *self, XEvent event) { +ltk_menu_mouse_release(ltk_widget *self, ltk_event *event) { ltk_menu *menu = (ltk_menu *)self; - size_t idx = get_entry_at_point(menu, event.xbutton.x, event.xbutton.y, NULL); + size_t idx = get_entry_at_point(menu, event->button.x, event->button.y, NULL); if (idx < menu->num_entries && idx == menu->pressed_entry) { ltk_window_unregister_all_popups(self->window); /* FIXME: give menu id and entry id */ @@ -622,33 +620,33 @@ ltk_menu_mouse_release(ltk_widget *self, XEvent event) { } static int -ltk_menu_mouse_press(ltk_widget *self, XEvent event) { +ltk_menu_mouse_press(ltk_widget *self, ltk_event *event) { ltk_menu *menu = (ltk_menu *)self; size_t idx; /* FIXME: configure scroll step */ - switch (event.xbutton.button) { - case 1: - idx = get_entry_at_point(menu, event.xbutton.x, event.xbutton.y, NULL); + switch (event->button.button) { + case LTK_BUTTONL: + idx = get_entry_at_point(menu, event->button.x, event->button.y, NULL); if (idx < menu->num_entries) { menu->pressed_entry = idx; self->dirty = 1; } break; - case 4: + case LTK_BUTTON4: ltk_menu_scroll(menu, 1, 0, 0, 0, 10); - handle_hover(menu, event.xbutton.x, event.xbutton.y); + handle_hover(menu, event->button.x, event->button.y); break; - case 5: + case LTK_BUTTON5: ltk_menu_scroll(menu, 0, 1, 0, 0, 10); - handle_hover(menu, event.xbutton.x, event.xbutton.y); + handle_hover(menu, event->button.x, event->button.y); break; - case 6: + case LTK_BUTTON6: ltk_menu_scroll(menu, 0, 0, 1, 0, 10); - handle_hover(menu, event.xbutton.x, event.xbutton.y); + handle_hover(menu, event->button.x, event->button.y); break; - case 7: + case LTK_BUTTON7: ltk_menu_scroll(menu, 0, 0, 0, 1, 10); - handle_hover(menu, event.xbutton.x, event.xbutton.y); + handle_hover(menu, event->button.x, event->button.y); break; default: break; @@ -807,19 +805,19 @@ handle_hover(ltk_menu *menu, int x, int y) { } static int -ltk_menu_motion_notify(ltk_widget *self, XEvent event) { - handle_hover((ltk_menu *)self, event.xmotion.x, event.xmotion.y); +ltk_menu_motion_notify(ltk_widget *self, ltk_event *event) { + handle_hover((ltk_menu *)self, event->motion.x, event->motion.y); return 1; } static int -ltk_menu_mouse_enter(ltk_widget *self, XEvent event) { - handle_hover((ltk_menu *)self, event.xbutton.x, event.xbutton.y); +ltk_menu_mouse_enter(ltk_widget *self, ltk_event *event) { + handle_hover((ltk_menu *)self, event->motion.x, event->motion.y); return 1; } static int -ltk_menu_mouse_leave(ltk_widget *self, XEvent event) { +ltk_menu_mouse_leave(ltk_widget *self, ltk_event *event) { (void)event; stop_scrolling((ltk_menu *)self); return 1; diff --git a/src/scrollbar.c b/src/scrollbar.c @@ -24,6 +24,7 @@ #include <X11/Xlib.h> #include <X11/Xutil.h> +#include "event.h" #include "memory.h" #include "color.h" #include "rect.h" @@ -36,8 +37,8 @@ #define MAX_SCROLLBAR_WIDTH 100 /* completely arbitrary */ static void ltk_scrollbar_draw(ltk_widget *self, ltk_rect clip); -static int ltk_scrollbar_mouse_press(ltk_widget *self, XEvent event); -static int ltk_scrollbar_motion_notify(ltk_widget *self, XEvent event); +static int ltk_scrollbar_mouse_press(ltk_widget *self, ltk_event *event); +static int ltk_scrollbar_motion_notify(ltk_widget *self, ltk_event *event); static void ltk_scrollbar_destroy(ltk_widget *self, int shallow); static struct ltk_widget_vtable vtable = { @@ -164,12 +165,12 @@ ltk_scrollbar_draw(ltk_widget *self, ltk_rect clip) { } static int -ltk_scrollbar_mouse_press(ltk_widget *self, XEvent event) { +ltk_scrollbar_mouse_press(ltk_widget *self, ltk_event *event) { ltk_scrollbar *sc = (ltk_scrollbar *)self; int max_pos; - if (event.xbutton.button != 1) + if (event->button.button != LTK_BUTTONL) return 0; - int ex = event.xbutton.x, ey = event.xbutton.y; + int ex = event->button.x, ey = event->button.y; ltk_rect handle_rect = get_handle_rect(sc); if (sc->orient == LTK_HORIZONTAL) { if (ex < handle_rect.x || ex > handle_rect.x + handle_rect.w) { @@ -187,8 +188,8 @@ ltk_scrollbar_mouse_press(ltk_widget *self, XEvent event) { else if (sc->cur_pos > max_pos) sc->cur_pos = max_pos; sc->callback(sc->callback_data); - sc->last_mouse_x = event.xbutton.x; - sc->last_mouse_y = event.xbutton.y; + sc->last_mouse_x = event->button.x; + sc->last_mouse_y = event->button.y; return 1; } @@ -218,19 +219,19 @@ ltk_scrollbar_scroll(ltk_widget *self, int delta, int scaled) { } static int -ltk_scrollbar_motion_notify(ltk_widget *self, XEvent event) { +ltk_scrollbar_motion_notify(ltk_widget *self, ltk_event *event) { ltk_scrollbar *sc = (ltk_scrollbar *)self; int delta; if (self->state != LTK_PRESSED) { return 1; } if (sc->orient == LTK_HORIZONTAL) - delta = event.xbutton.x - sc->last_mouse_x; + delta = event->button.x - sc->last_mouse_x; else - delta = event.xbutton.y - sc->last_mouse_y; + delta = event->button.y - sc->last_mouse_y; ltk_scrollbar_scroll(self, delta, 1); - sc->last_mouse_x = event.xbutton.x; - sc->last_mouse_y = event.xbutton.y; + sc->last_mouse_x = event->button.x; + sc->last_mouse_y = event->button.y; return 0; } diff --git a/src/surface_cache.c b/src/surface_cache.c @@ -14,6 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#include "graphics.h" #include "surface_cache.h" #include "memory.h" @@ -50,7 +51,7 @@ struct cache_surface { struct ltk_surface_cache { /* FIXME: many widgets won't use named keys anyways, so this is a bit wasteful */ - ltk_window *window; + ltk_renderdata *renderdata; struct named_cache_widget_entry named_keys[LTK_NUM_WIDGETS]; struct cache_surface **surfaces; size_t surfaces_num; /* total number of stored surfaces */ @@ -68,9 +69,9 @@ struct ltk_surface_cache { */ ltk_surface_cache * -ltk_surface_cache_create(ltk_window *window) { +ltk_surface_cache_create(ltk_renderdata *renderdata) { ltk_surface_cache *sc = ltk_malloc(sizeof(ltk_surface_cache)); - sc->window = window; + sc->renderdata = renderdata; for (int i = 0; i < LTK_NUM_WIDGETS; i++) { sc->named_keys[i].entries = NULL; sc->named_keys[i].entries_num = 0; @@ -194,7 +195,7 @@ ltk_surface_cache_get_surface(ltk_surface_cache_key *key, ltk_surface **s_ret) { c->surfaces[i] = NULL; } struct cache_surface *cs = ltk_malloc(sizeof(struct cache_surface)); - cs->s = ltk_surface_create(c->window, key->min_w, key->min_h); + cs->s = ltk_surface_create(c->renderdata, key->min_w, key->min_h); cs->key = key; key->s = cs; c->surfaces[0] = cs; @@ -216,7 +217,7 @@ ltk_surface_cache_get_surface(ltk_surface_cache_key *key, ltk_surface **s_ret) { struct cache_surface *cs = c->surfaces[c->surfaces_num]; c->surfaces_num++; c->surfaces_realnum++; - cs->s = ltk_surface_create(c->window, key->min_w, key->min_h); + cs->s = ltk_surface_create(c->renderdata, key->min_w, key->min_h); cs->key = key; key->s = cs; c->free_pixels -= (long)key->min_w * key->min_h; @@ -309,7 +310,7 @@ ltk_surface_cache_get_surface(ltk_surface_cache_key *key, ltk_surface **s_ret) { if (!c->surfaces[0]) c->surfaces[0] = ltk_malloc(sizeof(struct cache_surface)); struct cache_surface *cs = c->surfaces[0]; - cs->s = ltk_surface_create(c->window, key->min_w, key->min_h); + cs->s = ltk_surface_create(c->renderdata, key->min_w, key->min_h); cs->key = key; key->s = cs; c->surfaces_num = 1; diff --git a/src/surface_cache.h b/src/surface_cache.h @@ -13,7 +13,7 @@ typedef struct ltk_surface_cache_key ltk_surface_cache_key; #include "ltk.h" #include "graphics.h" -ltk_surface_cache *ltk_surface_cache_create(ltk_window *window); +ltk_surface_cache *ltk_surface_cache_create(ltk_renderdata *renderdata); void ltk_surface_cache_destroy(ltk_surface_cache *cache); ltk_surface_cache_key *ltk_surface_cache_get_named_key(ltk_surface_cache *cache, ltk_widget_type type, int id, int min_w, int min_h); ltk_surface_cache_key *ltk_surface_cache_get_unnamed_key(ltk_surface_cache *cache, int min_w, int min_h); diff --git a/src/text.h b/src/text.h @@ -25,6 +25,7 @@ typedef struct ltk_text_line ltk_text_line; /* typedef struct ltk_text_context ltk_text_context; */ /* FIXME: something to hold display, etc. to avoid circular reference between window and text context */ +/* FIXME: this is done now (ltk_renderdata), just need to use it here... */ ltk_text_context *ltk_text_context_create(ltk_window *window, char *default_font); void ltk_text_context_destroy(ltk_text_context *ctx); diff --git a/src/text_pango.c b/src/text_pango.c @@ -26,6 +26,7 @@ #include <pango/pangoxft.h> +#include "xlib_shared.h" #include "memory.h" #include "color.h" #include "rect.h" @@ -52,7 +53,7 @@ ltk_text_context * ltk_text_context_create(ltk_window *window, char *default_font) { ltk_text_context *ctx = ltk_malloc(sizeof(ltk_text_context)); ctx->window = window; - ctx->fontmap = pango_xft_get_font_map(window->dpy, window->screen); + ctx->fontmap = pango_xft_get_font_map(window->renderdata->dpy, window->renderdata->screen); ctx->context = pango_font_map_create_context(ctx->fontmap); ctx->default_font = ltk_strdup(default_font); return ctx; diff --git a/src/text_stb.c b/src/text_stb.c @@ -29,6 +29,7 @@ #include "khash.h" #include "stb_truetype.h" /* http://nothings.org/stb/stb_truetype.h */ +#include "xlib_shared.h" #include "memory.h" #include "color.h" #include "rect.h" @@ -591,7 +592,7 @@ ltk_text_line_draw(ltk_text_line *tl, ltk_surface *s, ltk_color *color, int x, i if (w <= 0 || h <= 0) return; Drawable d = ltk_surface_get_drawable(s); - XImage *img = XGetImage(tl->ctx->window->dpy, d, x, y, w, h, 0xFFFFFF, ZPixmap); + XImage *img = XGetImage(tl->ctx->window->renderdata->dpy, d, x, y, w, h, 0xFFFFFF, ZPixmap); int last_break = 0; for (int i = 0; i < tl->lines; i++) { @@ -607,7 +608,7 @@ ltk_text_line_draw(ltk_text_line *tl, ltk_surface *s, ltk_color *color, int x, i } last_break = next_break; } - XPutImage(tl->ctx->window->dpy, d, tl->ctx->window->gc, img, 0, 0, x, y, w, h); + XPutImage(tl->ctx->window->renderdata->dpy, d, tl->ctx->window->renderdata->gc, img, 0, 0, x, y, w, h); XDestroyImage(img); } diff --git a/src/theme.c b/src/theme.c @@ -1,3 +1,5 @@ +#include "graphics.h" +#include "surface_cache.h" #include "util.h" #include "theme.h" #include "memory.h" @@ -48,7 +50,7 @@ ltk_theme_handle_value(ltk_window *window, char *debug_name, const char *prop, c entry->initialized = 1; break; case THEME_COLOR: - if (ltk_color_create(window->dpy, window->vis, window->cm, value, entry->ptr.color)) { + if (ltk_color_create(window->renderdata, value, entry->ptr.color)) { ltk_warn("Unable to create color '%s' for property '%s:%s'.\n", value, debug_name, prop); return 1; } else { @@ -110,7 +112,7 @@ ltk_theme_fill_defaults(ltk_window *window, char *debug_name, ltk_theme_parseinf e->initialized = 1; break; case THEME_COLOR: - if (ltk_color_create(window->dpy, window->vis, window->cm, e->defaultval.color, e->ptr.color)) { + if (ltk_color_create(window->renderdata, e->defaultval.color, e->ptr.color)) { ltk_warn("Unable to create default color '%s' for property '%s:%s'.\n", e->defaultval.color, debug_name, e->key); return 1; } else { @@ -145,7 +147,7 @@ ltk_theme_uninitialize(ltk_window *window, ltk_theme_parseinfo *parseinfo, size_ e->initialized = 0; break; case THEME_COLOR: - ltk_color_destroy(window->dpy, window->vis, window->cm, e->ptr.color); + ltk_color_destroy(window->renderdata, e->ptr.color); e->initialized = 0; break; case THEME_INT: diff --git a/src/theme.h b/src/theme.h @@ -38,6 +38,7 @@ typedef struct { int initialized; } ltk_theme_parseinfo; +/* FIXME: this only needs renderdata, not window */ /* Both return 1 on error, 0 on success */ int ltk_theme_handle_value(ltk_window *window, char *debug_name, const char *prop, const char *value, ltk_theme_parseinfo *parseinfo, size_t len, int *sorted); int ltk_theme_fill_defaults(ltk_window *window, char *debug_name, ltk_theme_parseinfo *parseinfo, size_t len); diff --git a/src/widget.c b/src/widget.c @@ -22,11 +22,9 @@ */ #include <stdarg.h> - -#include <X11/Xlib.h> -#include <X11/Xutil.h> #include <stdint.h> +#include "event.h" #include "rect.h" #include "widget.h" #include "color.h" @@ -129,20 +127,20 @@ ltk_widget_change_state(ltk_widget *widget) { } void -ltk_widget_mouse_press_event(ltk_widget *widget, XEvent event) { +ltk_widget_mouse_press_event(ltk_widget *widget, ltk_event *event) { if (!widget || widget->state == LTK_DISABLED) return; int default_handler = 1; if (widget->vtable->mouse_press) default_handler = widget->vtable->mouse_press(widget, event); if (default_handler) { - if (event.xbutton.button == 1) + if (event->button.button == LTK_BUTTONL) ltk_window_set_pressed_widget(widget->window, widget); } } void -ltk_widget_mouse_release_event(ltk_widget *widget, XEvent event) { +ltk_widget_mouse_release_event(ltk_widget *widget, ltk_event *event) { if (!widget || widget->state == LTK_DISABLED) return; if (widget->vtable->mouse_release) @@ -151,7 +149,7 @@ ltk_widget_mouse_release_event(ltk_widget *widget, XEvent event) { } void -ltk_widget_motion_notify_event(ltk_widget *widget, XEvent event) { +ltk_widget_motion_notify_event(ltk_widget *widget, ltk_event *event) { /* FIXME: THIS WHOLE STATE HANDLING IS STILL PARTIALLY BROKEN */ /* FIXME: need to bring back hover state to make enter/leave work properly */ /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */ diff --git a/src/widget.h b/src/widget.h @@ -17,9 +17,8 @@ #ifndef _LTK_WIDGET_H_ #define _LTK_WIDGET_H_ -#include <X11/Xlib.h> -#include <X11/Xutil.h> #include "rect.h" +#include "event.h" /* FIXME: SORT OUT INCLUDES PROPERLY! */ @@ -85,14 +84,16 @@ struct ltk_widget { char hidden; }; +/* FIXME: just give the structs for the actual event type here instead + of the generic ltk_event */ struct ltk_widget_vtable { - void (*key_press) (struct ltk_widget *, XEvent); - void (*key_release) (struct ltk_widget *, XEvent); - int (*mouse_press) (struct ltk_widget *, XEvent); - int (*mouse_release) (struct ltk_widget *, XEvent); - int (*motion_notify) (struct ltk_widget *, XEvent); - int (*mouse_leave) (struct ltk_widget *, XEvent); - int (*mouse_enter) (struct ltk_widget *, XEvent); + void (*key_press) (struct ltk_widget *, ltk_event *); + void (*key_release) (struct ltk_widget *, ltk_event *); + int (*mouse_press) (struct ltk_widget *, ltk_event *); + int (*mouse_release) (struct ltk_widget *, ltk_event *); + int (*motion_notify) (struct ltk_widget *, ltk_event *); + int (*mouse_leave) (struct ltk_widget *, ltk_event *); + int (*mouse_enter) (struct ltk_widget *, ltk_event *); void (*resize) (struct ltk_widget *); void (*hide) (struct ltk_widget *); @@ -113,9 +114,9 @@ int ltk_widget_destroy_cmd(struct ltk_window *window, char **tokens, size_t num_ void ltk_fill_widget_defaults(ltk_widget *widget, const char *id, struct ltk_window *window, struct ltk_widget_vtable *vtable, int w, int h); void ltk_widget_change_state(ltk_widget *widget); -void ltk_widget_mouse_press_event(ltk_widget *widget, XEvent event); -void ltk_widget_mouse_release_event(ltk_widget *widget, XEvent event); -void ltk_widget_motion_notify_event(ltk_widget *widget, XEvent event); +void ltk_widget_mouse_press_event(ltk_widget *widget, ltk_event *event); +void ltk_widget_mouse_release_event(ltk_widget *widget, ltk_event *event); +void ltk_widget_motion_notify_event(ltk_widget *widget, ltk_event *event); int ltk_widget_id_free(const char *id); ltk_widget *ltk_get_widget(const char *id, ltk_widget_type type, char **errstr); void ltk_set_widget(ltk_widget *widget, const char *id); diff --git a/src/xlib_shared.h b/src/xlib_shared.h @@ -0,0 +1,20 @@ +#ifndef XLIB_SHARED_H +#define XLIB_SHARED_H + +#include <X11/Xlib.h> +#include <X11/extensions/Xdbe.h> + +struct ltk_renderdata { + Display *dpy; + Visual *vis; + Colormap cm; + GC gc; + int screen; + Atom wm_delete_msg; + Window xwindow; + XdbeBackBuffer back_buf; + Drawable drawable; + int depth; +}; + +#endif /* XLIB_SHARED_H */