diff options
Diffstat (limited to 'window-xlib.c')
-rw-r--r-- | window-xlib.c | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/window-xlib.c b/window-xlib.c new file mode 100644 index 0000000..ea5f61a --- /dev/null +++ b/window-xlib.c @@ -0,0 +1,210 @@ +#include <cairo-xlib.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <X11/Xlib.h> +#include <X11/Xatom.h> +#include <X11/Xutil.h> + +#include "runes.h" + +static char *atom_names[RUNES_NUM_ATOMS] = { + "WM_DELETE_WINDOW", + "_NET_WM_PING", + "_NET_WM_PID", + "_NET_WM_ICON_NAME", + "_NET_WM_NAME", + "UTF8_STRING" +}; + +static void runes_init_wm_properties(RunesWindowBackend *w, int argc, char *argv[]) +{ + pid_t pid; + XClassHint class_hints = { "runes", "runes" }; + XWMHints wm_hints; + XSizeHints normal_hints; + + wm_hints.flags = InputHint | StateHint; + wm_hints.input = True; + wm_hints.initial_state = NormalState; + + /* XXX */ + normal_hints.flags = 0; + + XInternAtoms(w->dpy, atom_names, RUNES_NUM_ATOMS, False, w->atoms); + XSetWMProtocols(w->dpy, w->w, w->atoms, RUNES_NUM_PROTOCOL_ATOMS); + + Xutf8SetWMProperties(w->dpy, w->w, "runes", "runes", argv, argc, &normal_hints, &wm_hints, &class_hints); + + pid = getpid(); + XChangeProperty(w->dpy, w->w, w->atoms[RUNES_ATOM_NET_WM_PID], XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&pid, 1); + + XChangeProperty(w->dpy, w->w, w->atoms[RUNES_ATOM_NET_WM_ICON_NAME], w->atoms[RUNES_ATOM_UTF8_STRING], 8, PropModeReplace, (unsigned char *)"runes", 5); + XChangeProperty(w->dpy, w->w, w->atoms[RUNES_ATOM_NET_WM_NAME], w->atoms[RUNES_ATOM_UTF8_STRING], 8, PropModeReplace, (unsigned char *)"runes", 5); +} + +void runes_window_backend_init(RunesTerm *t, int argc, char *argv[]) +{ + RunesWindowBackend *w; + unsigned long white; + XIM im; + + w = &t->w; + + w->dpy = XOpenDisplay(NULL); + white = WhitePixel(w->dpy, DefaultScreen(w->dpy)); + w->w = XCreateSimpleWindow( + w->dpy, DefaultRootWindow(w->dpy), + 0, 0, 240, 80, 0, white, white + ); + + XSelectInput(w->dpy, w->w, StructureNotifyMask); + XMapWindow(w->dpy, w->w); + w->gc = XCreateGC(w->dpy, w->w, 0, NULL); + XSetForeground(w->dpy, w->gc, white); + + for (;;) { + XEvent e; + + XNextEvent(w->dpy, &e); + if (e.type == MapNotify) { + break; + } + } + + XSetLocaleModifiers(""); + im = XOpenIM(w->dpy, NULL, NULL, NULL); + w->ic = XCreateIC( + im, + XNInputStyle, XIMPreeditNothing | XIMStatusNothing, + XNClientWindow, w->w, + XNFocusWindow, w->w, + NULL + ); + if (w->ic == NULL) { + fprintf(stderr, "failed\n"); + exit(1); + } + + runes_init_wm_properties(w, argc, argv); +} + +cairo_surface_t *runes_window_backend_surface_create(RunesTerm *t) +{ + RunesWindowBackend *w; + Visual *vis; + XWindowAttributes attrs; + + w = &t->w; + XGetWindowAttributes(w->dpy, w->w, &attrs); + vis = DefaultVisual(w->dpy, DefaultScreen(w->dpy)); + return cairo_xlib_surface_create(w->dpy, w->w, vis, attrs.width, attrs.height); +} + +static void runes_get_next_event(uv_work_t *req) +{ + RunesXlibLoopData *data; + + data = (RunesXlibLoopData *)req->data; + XNextEvent(data->data.t->w.dpy, &data->e); +} + +static void runes_process_event(uv_work_t *req, int status) +{ + RunesXlibLoopData *data; + XEvent *e; + RunesTerm *t; + RunesWindowBackend *w; + + UNUSED(status); + + data = ((RunesXlibLoopData *)req->data); + e = &data->e; + t = data->data.t; + w = &t->w; + + if (!XFilterEvent(e, None)) { + switch (e->type) { + case KeyPress: { + char *buf = NULL; + size_t len = 8; + KeySym sym; + Status s; + size_t chars; + + buf = malloc(len); + + for (;;) { + chars = Xutf8LookupString(w->ic, &e->xkey, buf, len - 1, &sym, &s); + if (s == XBufferOverflow) { + len = chars + 1; + buf = realloc(buf, len); + continue; + } + break; + } + + runes_handle_keyboard_event(t, buf, chars); + free(buf); + break; + } + case ClientMessage: { + Atom a = e->xclient.data.l[0]; + if (a == w->atoms[RUNES_ATOM_WM_DELETE_WINDOW]) { + runes_handle_close_window(t); + } + else if (a == w->atoms[RUNES_ATOM_NET_WM_PING]) { + e->xclient.window = DefaultRootWindow(w->dpy); + XSendEvent( + w->dpy, e->xclient.window, False, + SubstructureNotifyMask | SubstructureRedirectMask, + e + ); + } + break; + } + default: + break; + } + } + + if (t->loop) { + uv_queue_work(t->loop, req, runes_get_next_event, runes_process_event); + } + else { + free(req); + } +} + +void runes_window_backend_loop_init(RunesTerm *t, uv_loop_t *loop) +{ + RunesWindowBackend *w; + unsigned long mask; + void *data; + + w = &t->w; + + XGetICValues(w->ic, XNFilterEvents, &mask, NULL); + XSelectInput(w->dpy, w->w, mask|KeyPressMask|StructureNotifyMask); + XSetICFocus(w->ic); + + data = malloc(sizeof(RunesXlibLoopData)); + ((RunesLoopData *)data)->req.data = data; + ((RunesLoopData *)data)->t = t; + + uv_queue_work(loop, data, runes_get_next_event, runes_process_event); +} + +void runes_window_backend_cleanup(RunesTerm *t) +{ + RunesWindowBackend *w; + XIM im; + + w = &t->w; + im = XIMOfIC(w->ic); + XDestroyIC(w->ic); + XCloseIM(im); + XFreeGC(w->dpy, w->gc); + XDestroyWindow(w->dpy, w->w); + XCloseDisplay(w->dpy); +} |