From 518c12b0528cfafa5bce4650d080e2b8bb83780e Mon Sep 17 00:00:00 2001 From: "Michael D. Lowis" Date: Fri, 25 Mar 2022 16:07:02 -0400 Subject: [PATCH] added event handling scaffolding --- src/uitest/main.c | 5 +- src/uitest/ui.h | 181 +++++++++++++++-------------- src/uitest/ui_window.c | 258 ++++++++++++++++++++++++++++++++++++++++- src/uitest/x11.c | 34 +----- 4 files changed, 351 insertions(+), 127 deletions(-) diff --git a/src/uitest/main.c b/src/uitest/main.c index 76fbabf..febf2ef 100644 --- a/src/uitest/main.c +++ b/src/uitest/main.c @@ -1,10 +1,13 @@ #include + #include "ui.h" +#define INCLUDE_DEFS +#include "config.h" int main(int argc, char** argv) { UIWidget* win = UI_MakeWindow(640, 480); UI_ShowWindow(win); - sleep(60); + UI_StartEventLoop(NULL); return 0; } diff --git a/src/uitest/ui.h b/src/uitest/ui.h index 2f77381..a06d75f 100644 --- a/src/uitest/ui.h +++ b/src/uitest/ui.h @@ -14,6 +14,7 @@ enum { }; typedef struct XConf { + Atom XA_DELETE, XA_GOTO; Bool error; int state, fd, screen, mods; Window root; @@ -33,91 +34,93 @@ extern XConf X; // CLIPBOARD = 1 //}; // -///* key definitions */ -//enum Keys { -// /* Define some runes in the private use area of unicode to represent -// * special keys */ -// KEY_F1 = (0xE000+0), -// KEY_F2 = (0xE000+1), -// KEY_F3 = (0xE000+2), -// KEY_F4 = (0xE000+3), -// KEY_F5 = (0xE000+4), -// KEY_F6 = (0xE000+5), -// KEY_F7 = (0xE000+6), -// KEY_F8 = (0xE000+7), -// KEY_F9 = (0xE000+8), -// KEY_F10 = (0xE000+9), -// KEY_F11 = (0xE000+10), -// KEY_F12 = (0xE000+11), -// KEY_INSERT = (0xE000+12), -// KEY_DELETE = (0xE000+13), -// KEY_HOME = (0xE000+14), -// KEY_END = (0xE000+15), -// KEY_PGUP = (0xE000+16), -// KEY_PGDN = (0xE000+17), -// KEY_UP = (0xE000+18), -// KEY_DOWN = (0xE000+19), -// KEY_RIGHT = (0xE000+20), -// KEY_LEFT = (0xE000+21), -// -// /* ASCII Control Characters */ -// KEY_CTRL_TILDE = 0x00, -// KEY_CTRL_2 = 0x00, -// KEY_CTRL_A = 0x01, -// KEY_CTRL_B = 0x02, -// KEY_CTRL_C = 0x03, -// KEY_CTRL_D = 0x04, -// KEY_CTRL_E = 0x05, -// KEY_CTRL_F = 0x06, -// KEY_CTRL_G = 0x07, -// KEY_BACKSPACE = 0x08, -// KEY_CTRL_H = 0x08, -// KEY_TAB = 0x09, -// KEY_CTRL_I = 0x09, -// KEY_CTRL_J = 0x0A, -// KEY_CTRL_K = 0x0B, -// KEY_CTRL_L = 0x0C, -// KEY_ENTER = 0x0D, -// KEY_CTRL_M = 0x0D, -// KEY_CTRL_N = 0x0E, -// KEY_CTRL_O = 0x0F, -// KEY_CTRL_P = 0x10, -// KEY_CTRL_Q = 0x11, -// KEY_CTRL_R = 0x12, -// KEY_CTRL_S = 0x13, -// KEY_CTRL_T = 0x14, -// KEY_CTRL_U = 0x15, -// KEY_CTRL_V = 0x16, -// KEY_CTRL_W = 0x17, -// KEY_CTRL_X = 0x18, -// KEY_CTRL_Y = 0x19, -// KEY_CTRL_Z = 0x1A, -// KEY_ESCAPE = 0x1B, -// KEY_CTRL_LSQ_BRACKET = 0x1B, -// KEY_CTRL_3 = 0x1B, -// KEY_CTRL_4 = 0x1C, -// KEY_CTRL_BACKSLASH = 0x1C, -// KEY_CTRL_5 = 0x1D, -// KEY_CTRL_RSQ_BRACKET = 0x1D, -// KEY_CTRL_6 = 0x1E, -// KEY_CTRL_7 = 0x1F, -// KEY_CTRL_SLASH = 0x1F, -// KEY_CTRL_UNDERSCORE = 0x1F, -//}; -// -///* Key modifier masks */ -//enum { -// ModNone = 0, -// ModShift = (1 << 0), -// ModCapsLock = (1 << 1), -// ModCtrl = (1 << 2), -// ModAlt = (1 << 3), -// ModNumLock = (1 << 4), -// ModScrollLock = (1 << 5), -// ModWindows = (1 << 6), -// ModOneOrMore = (ModCtrl|ModAlt), -// ModAny = -1 -//}; +/* key definitions */ +enum Keys { + RUNE_ERR = 0xFFFD, + + /* Define some runes in the private use area of unicode to represent + * special keys */ + KEY_F1 = (0xE000+0), + KEY_F2 = (0xE000+1), + KEY_F3 = (0xE000+2), + KEY_F4 = (0xE000+3), + KEY_F5 = (0xE000+4), + KEY_F6 = (0xE000+5), + KEY_F7 = (0xE000+6), + KEY_F8 = (0xE000+7), + KEY_F9 = (0xE000+8), + KEY_F10 = (0xE000+9), + KEY_F11 = (0xE000+10), + KEY_F12 = (0xE000+11), + KEY_INSERT = (0xE000+12), + KEY_DELETE = (0xE000+13), + KEY_HOME = (0xE000+14), + KEY_END = (0xE000+15), + KEY_PGUP = (0xE000+16), + KEY_PGDN = (0xE000+17), + KEY_UP = (0xE000+18), + KEY_DOWN = (0xE000+19), + KEY_RIGHT = (0xE000+20), + KEY_LEFT = (0xE000+21), + + /* ASCII Control Characters */ + KEY_CTRL_TILDE = 0x00, + KEY_CTRL_2 = 0x00, + KEY_CTRL_A = 0x01, + KEY_CTRL_B = 0x02, + KEY_CTRL_C = 0x03, + KEY_CTRL_D = 0x04, + KEY_CTRL_E = 0x05, + KEY_CTRL_F = 0x06, + KEY_CTRL_G = 0x07, + KEY_BACKSPACE = 0x08, + KEY_CTRL_H = 0x08, + KEY_TAB = 0x09, + KEY_CTRL_I = 0x09, + KEY_CTRL_J = 0x0A, + KEY_CTRL_K = 0x0B, + KEY_CTRL_L = 0x0C, + KEY_ENTER = 0x0D, + KEY_CTRL_M = 0x0D, + KEY_CTRL_N = 0x0E, + KEY_CTRL_O = 0x0F, + KEY_CTRL_P = 0x10, + KEY_CTRL_Q = 0x11, + KEY_CTRL_R = 0x12, + KEY_CTRL_S = 0x13, + KEY_CTRL_T = 0x14, + KEY_CTRL_U = 0x15, + KEY_CTRL_V = 0x16, + KEY_CTRL_W = 0x17, + KEY_CTRL_X = 0x18, + KEY_CTRL_Y = 0x19, + KEY_CTRL_Z = 0x1A, + KEY_ESCAPE = 0x1B, + KEY_CTRL_LSQ_BRACKET = 0x1B, + KEY_CTRL_3 = 0x1B, + KEY_CTRL_4 = 0x1C, + KEY_CTRL_BACKSLASH = 0x1C, + KEY_CTRL_5 = 0x1D, + KEY_CTRL_RSQ_BRACKET = 0x1D, + KEY_CTRL_6 = 0x1E, + KEY_CTRL_7 = 0x1F, + KEY_CTRL_SLASH = 0x1F, + KEY_CTRL_UNDERSCORE = 0x1F, +}; + +/* Key modifier masks */ +enum { + ModNone = 0, + ModShift = (1 << 0), + ModCapsLock = (1 << 1), + ModCtrl = (1 << 2), + ModAlt = (1 << 3), + ModNumLock = (1 << 4), + ModScrollLock = (1 << 5), + ModWindows = (1 << 6), + ModOneOrMore = (ModCtrl|ModAlt), + ModAny = -1 +}; // //typedef struct { // int mods; @@ -188,9 +191,10 @@ typedef struct { struct UIWidget; typedef struct { + void (*clientmsg)(struct UIWidget* widget, long type, long value); void (*resize)(struct UIWidget* widget, long maxw, long maxh); - void (*draw)(struct UIWidget* widget, long maxw, long maxh); - long (*process)(struct UIWidget* widget, UIEvent* ev); + void (*redraw)(struct UIWidget* widget, long maxw, long maxh); + void (*keypress)(struct UIWidget* widget, long mods, long key); } UIWidgetFuncs; typedef struct UIWidget { @@ -203,6 +207,7 @@ typedef struct UIWidget { UIWidget* UI_MakeWindow(long width, long height); UIWidget* UI_MakeDialog(void); -void UI_StartEventLoop(void (*)(UIWidget*, UIEvent*)); +void UI_StartEventLoop(void (*onevent)(int fd, int events)); +int UI_MonitorDescriptor(int fd); void UI_ShowWindow(UIWidget* w); void UI_HideWindow(UIWidget* w); diff --git a/src/uitest/ui_window.c b/src/uitest/ui_window.c index 3a169f3..a3dfa2f 100644 --- a/src/uitest/ui_window.c +++ b/src/uitest/ui_window.c @@ -1,5 +1,12 @@ #include +#include + #include "ui.h" +#include "config.h" + +#ifndef MAX_DESCRIPTORS +#define MAX_DESCRIPTORS 256 +#endif typedef struct UIWindow { UIWidget widget; @@ -7,11 +14,166 @@ typedef struct UIWindow { struct UIWindow* next; } UIWindow; -UIWindow* WindowList = NULL; +static int Num_Descriptors = 0; +static struct pollfd Descriptors[MAX_DESCRIPTORS]; +static UIWindow* WindowList = NULL; + +static UIWindow* get_window(Window id) +{ + UIWindow* win = WindowList; + for (; win && win->xwin.winid != id; win = win->next); + return win; +} + +static void xkeypress(XEvent* e) +{ + /* map special keys to a special section of unicode for "private use" */ + static uint32_t keymap[256] = { + /* Function keys */ + [0xBE] = KEY_F1, [0xBF] = KEY_F2, [0xC0] = KEY_F3, [0xC1] = KEY_F4, + [0xC2] = KEY_F5, [0xC3] = KEY_F6, [0xC4] = KEY_F7, [0xC5] = KEY_F8, + [0xC6] = KEY_F9, [0xC7] = KEY_F10, [0xC8] = KEY_F11, [0xC9] = KEY_F12, + /* Navigation keys */ + [0x50] = KEY_HOME, [0x51] = KEY_LEFT, [0x52] = KEY_UP, + [0x53] = KEY_RIGHT, [0x54] = KEY_DOWN, [0x55] = KEY_PGUP, + [0x56] = KEY_PGDN, [0x57] = KEY_END, + /* Control keys */ + [0x08] = '\b', [0x09] = '\t', [0x0d] = '\n', [0x0a] = '\n', + /* Miscellaneous */ + [0x63] = KEY_INSERT, [0x1B] = KEY_ESCAPE, [0xFF] = KEY_DELETE, + }; + + uint32_t rune; + char buf[8]; + KeySym key; + Status status; + + UIWindow* win = get_window(e->xany.window); + if (win && win->widget.funcs->keypress) + { + printf("%s(%lu)\n", __func__, win->xwin.winid); + + /* Read the key string */ + if (win->xwin.xic) + { + Xutf8LookupString( + win->xwin.xic, &(e->xkey), buf, sizeof(buf), &key, &status); + } + else + { + XLookupString(&(e->xkey), buf, sizeof(buf), &key, 0); + } + + /* if it's ascii, just return it */ + if (key >= 0x20 && key <= 0x7F) + { + rune = (uint32_t)key; + } + else + { + /* lookup the key by keysym */ + key = ((key & 0xFF00) == 0xFF00 ? keymap[key & 0xFF] : key); + rune = (!key ? RUNE_ERR : key); + } + + if (key != RUNE_ERR) + { + int mods = e->xkey.state & (ModCtrl|ModShift|ModAlt); + win->widget.funcs->keypress(&(win->widget), mods, tolower(rune)); + } + + printf("key: 0x%x\n", rune); + } +} + +static void xmousebtn(XEvent* e) +{ + UIWindow* win = get_window(e->xany.window); + if (win) + { + printf("%s(%lu)\n", __func__, win->xwin.winid); + } +} + +static void xbtnmotion(XEvent* e) +{ + UIWindow* win = get_window(e->xany.window); + if (win) + { + printf("%s(%lu)\n", __func__, win->xwin.winid); + } +} + +static void xclientmsg(XEvent* e) +{ + UIWindow* win = get_window(e->xany.window); + if (win) + { + printf("%s(%lu)\n", __func__, win->xwin.winid); + + if ((Atom)(e->xclient.data.l[0]) == X.XA_DELETE) + { +// win_quit(); + } + else if (e->xclient.message_type == X.XA_GOTO) + { +// x11_seturgent(x, 1); +// win_setln(e->xclient.data.l[0]); + } + } +} + +static void xresize(XEvent* e) +{ + UIWindow* win = get_window(e->xany.window); + if (win) + { + printf("%s(%lu)\n", __func__, win->xwin.winid); + } +} + +static void xmapnotify(XEvent* e) +{ + UIWindow* win = get_window(e->xany.window); + if (win) + { + printf("%s(%lu)\n", __func__, win->xwin.winid); + } +} + +static void xenternotify(XEvent* e) +{ + UIWindow* win = get_window(e->xany.window); + if (win) + { + printf("%s(%lu)\n", __func__, win->xwin.winid); + } +} + +static void xinit(void) +{ + static int initialized = 0; + if (!initialized) { + X11_Init(); + X.eventfns[KeyPress] = xkeypress; + X.eventfns[ButtonPress] = xmousebtn; + X.eventfns[ButtonRelease] = xmousebtn; + X.eventfns[MotionNotify] = xbtnmotion; + X.eventfns[ClientMessage] = xclientmsg; + X.eventfns[ConfigureNotify] = xresize; + X.eventfns[MapNotify] = xmapnotify; + X.eventfns[EnterNotify] = xenternotify; + X.XA_DELETE = XInternAtom(X.display, "WM_DELETE_WINDOW", False); + X.XA_GOTO = XInternAtom(X.display, "WM_DELETE_WINDOW", False); + Num_Descriptors = 0; + UI_MonitorDescriptor(ConnectionNumber(X.display)); + initialized = 1; + } +} UIWindow* make_window(void) { - if (!WindowList) { X11_Init(); } + xinit(); UIWindow* win = calloc(1, sizeof(UIWindow)); win->next = WindowList; WindowList = win; @@ -32,10 +194,94 @@ UIWidget* UI_MakeDialog(void) return &(win->widget); } -//void UI_StartEventLoop(void (*)(UIWidget*, UIEvent*)) -//{ -// /* TODO: implement event loop */ -//} +static void process_xevents(int events) +{ + if (events & (POLLHUP|POLLERR)) + { + /* kill X connection and cleanup windows */ + } + else if (events & POLLIN) + { + /* process the entire event queue */ + while (XEventsQueued(X.display, QueuedAfterReading)) + { + for (XEvent e; XPending(X.display);) + { + XNextEvent(X.display, &e); + if (!XFilterEvent(&e, None) && X.eventfns[e.type]) + { + X.eventfns[e.type](&e); + } + } + } + } + else + { + /* do nothing */ + } +} + + +static void process_descriptor(int fd, int events, void (*onevent)(int fd, int events)) +{ + if (events) + { + int xfd = ConnectionNumber(X.display); + if (fd == xfd) + { + process_xevents(events); + } + else + { + onevent(fd, events); + } + } +} + +void UI_StartEventLoop(void (*onevent)(int fd, int events)) +{ + int maxcount = 1000 / Timeout; + int count = 0; + + XSync(X.display, False); + while (Num_Descriptors) + { + /* Clear previous statuses in prep */ + for (int i = 0; i < Num_Descriptors; i++) + { + Descriptors[Num_Descriptors].events = 0; + } + + /* Poll the descriptor list until there is something to do */ + long ret = poll(Descriptors, Num_Descriptors, Timeout); + + /* Process the list of descriptors */ + for (int i = 0; i < Num_Descriptors; i++) + { + process_descriptor(Descriptors[i].fd, Descriptors[i].revents, onevent); + } + +// bool ready = poll_descriptors(Timeout); +// count += (ready ? -count : 1); +// if (count < maxcount) +// { +// xupdate(NULL); +// } + } +} + +int UI_MonitorDescriptor(int fd) +{ + int success = -1; + if (Num_Descriptors < MAX_DESCRIPTORS) + { + Descriptors[Num_Descriptors].fd = fd; + Descriptors[Num_Descriptors].events = POLLIN|POLLOUT; + Num_Descriptors++; + success = 0; + } + return success; +} void UI_ShowWindow(UIWidget* w) { diff --git a/src/uitest/x11.c b/src/uitest/x11.c index a415478..6caa967 100644 --- a/src/uitest/x11.c +++ b/src/uitest/x11.c @@ -1,4 +1,5 @@ #include +#include #include "ui.h" #include "config.h" @@ -13,27 +14,6 @@ static int onerror(Display* disp, XErrorEvent* ev) return 0; } -static void xkeypress(XEvent* e) -{} - -static void xmousebtn(XEvent* e) -{} - -static void xbtnmotion(XEvent* e) -{} - -static void xclientmsg(XEvent* e) -{} - -static void xresize(XEvent* e) -{} - -static void xmapnotify(XEvent* e) -{} - -static void xenternotify(XEvent* e) -{} - int X11_Init(void) { int ret = -1; @@ -53,16 +33,6 @@ int X11_Init(void) X.depth = DefaultDepth(X.display, X.screen); X.state = RUNNING; XSetErrorHandler(onerror); - - /* register event handlers */ - X.eventfns[KeyPress] = xkeypress; - X.eventfns[ButtonPress] = xmousebtn; - X.eventfns[ButtonRelease] = xmousebtn; - X.eventfns[MotionNotify] = xbtnmotion; - X.eventfns[ClientMessage] = xclientmsg; - X.eventfns[ConfigureNotify] = xresize; - X.eventfns[MapNotify] = xmapnotify; - X.eventfns[EnterNotify] = xenternotify; ret = 0; } @@ -155,7 +125,7 @@ void X11_ShowWindow(XWindow* w) } if (ev.type == ConfigureNotify) { - xresize(&ev); + X.eventfns[ConfigureNotify](&ev); } } while (ev.type != MapNotify); -- 2.51.0