summaryrefslogtreecommitdiff
path: root/xlib.c
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2006-10-12 09:18:40 +0000
committerRich Felker <dalias@aerifal.cx>2006-10-12 09:18:40 +0000
commit9c136f5f817ffe71b3ac4d92106e6d211e8b6e42 (patch)
tree8d8176fff5719ab3f4562ef2bae36dbb88a51d4f /xlib.c
parentb1810d2fc0312c36b65bf26cc411473ef3e91db9 (diff)
first try at porting to X. very broken, minimal functionality,
but it does work..
Diffstat (limited to 'xlib.c')
-rw-r--r--xlib.c375
1 files changed, 375 insertions, 0 deletions
diff --git a/xlib.c b/xlib.c
new file mode 100644
index 0000000..bb22e3e
--- /dev/null
+++ b/xlib.c
@@ -0,0 +1,375 @@
+/* uuterm, Copyright (C) 2006 Rich Felker; licensed under GNU GPL v2 only */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/select.h>
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/keysym.h>
+
+#include "uuterm.h"
+#include "ucf.h"
+
+struct priv
+{
+ int fd;
+ Display *display;
+ int screen;
+ Window window;
+ XIM im;
+ XIC ic;
+ GC wingc, cugc, bggc, fggc, maskgc;
+ Pixmap pixmap;
+ Pixmap *glyph_cache;
+ int *slices_y;
+ int curs_x, curs_y;
+ int curs_on;
+ unsigned long colors[16];
+};
+
+#if 0
+static int get_fb_size(struct uudisp *d)
+{
+ struct priv *p = (struct priv *)&d->priv;
+
+ if (ioctl(p->fb, FBIOGET_FSCREENINFO, &fix) < 0
+ || ioctl(p->fb, FBIOGET_VSCREENINFO, &var) < 0
+ || fix.type != FB_TYPE_PACKED_PIXELS)
+ return -1;
+
+ p->b.bytes_per_pixel = (var.bits_per_pixel+7)>>3;
+ p->b.line_stride = fix.line_length;
+ p->b.row_stride = fix.line_length * d->cell_h;
+
+ if (var.xres != p->xres || var.yres != p->yres) {
+ int w = var.xres / d->cell_w;
+ int h = var.yres / d->cell_h;
+ void *buf = uuterm_alloc(SLICE_BUF_SIZE(w, h, (d->cell_w+7)/8, d->cell_h));
+ if (!buf) return -1;
+ if (p->buf_mem) uuterm_free(p->buf_mem);
+ p->buf_mem = buf;
+ p->b.slices = dblbuf_setup_buf(w, h, (d->cell_w+7)/8, d->cell_h, buf);
+ p->xres = var.xres;
+ p->yres = var.yres;
+ d->w = w;
+ d->h = h;
+ p->b.repaint = 1;
+ p->b.curs_x = p->b.curs_y = 0;
+ }
+
+ return 0;
+}
+#endif
+
+int uudisp_open(struct uudisp *d)
+{
+ struct priv *p = (void *)&d->priv;
+ XGCValues values;
+ XVisualInfo vi;
+ char *s;
+ int px_w = 80*d->cell_w;
+ int px_h = 24*d->cell_h;
+ struct ucf *f = d->font;
+ const unsigned char *glyphs, *end;
+ int nglyphs = f->nglyphs;
+ GC gc;
+ int npages;
+ XImage *image;
+ int i, j, k;
+
+ if (!(p->display = XOpenDisplay(NULL)))
+ return -1;
+
+ p->fd = ConnectionNumber(p->display);
+ p->screen = DefaultScreen(p->display);
+ p->window = XCreateSimpleWindow(p->display,
+ DefaultRootWindow(p->display),
+ 0, 0, px_w, px_h, 1,
+ BlackPixel(p->display, p->screen),
+ BlackPixel(p->display, p->screen));
+ XSelectInput(p->display, p->window, KeyPressMask|ExposureMask);
+ XMapWindow(p->display, p->window);
+
+ d->w = 80;
+ d->h = 24;
+ p->slices_y = uuterm_alloc(240*sizeof(int));
+
+ //XSetLocaleModifiers("@im=none");
+ //p->im = XOpenIM(p->display, 0, 0, 0);
+ //p->ic = XCreateIC(p->im, XNInputStyle, XIMPreeditNothing|XIMStatusNothing);
+
+ p->pixmap = XCreatePixmap(p->display, p->window, px_w, px_h,
+ DefaultDepth(p->display, p->screen));
+
+ p->wingc = XCreateGC(p->display, p->window, 0, &values);
+ p->cugc = XCreateGC(p->display, p->window, 0, &values);
+ p->fggc = XCreateGC(p->display, p->pixmap, 0, &values);
+ p->bggc = XCreateGC(p->display, p->pixmap, 0, &values);
+ p->maskgc = XCreateGC(p->display, p->pixmap, 0, &values);
+ XSetFunction(p->display, p->cugc, GXxor);
+ XSetFunction(p->display, p->fggc, GXor);
+ XSetFunction(p->display, p->bggc, GXcopy);
+ XSetFunction(p->display, p->maskgc, GXandInverted);
+ XSetForeground(p->display, p->cugc, WhitePixel(p->display, p->screen));
+ XSetBackground(p->display, p->fggc, BlackPixel(p->display, p->screen));
+ XSetForeground(p->display, p->maskgc, WhitePixel(p->display, p->screen));
+ XSetBackground(p->display, p->maskgc, BlackPixel(p->display, p->screen));
+
+ npages = (nglyphs+1023) / 1024; // allows up to 64 pixel cell height..
+ p->glyph_cache = calloc(sizeof(p->glyph_cache[0]), npages);
+
+ glyphs = f->glyphs;
+ end = glyphs + nglyphs*f->S;
+
+ for (i=0; i<npages; i++) {
+ unsigned char data[1024*f->S], *g = data;
+
+ if (BitmapBitOrder(p->display) == LSBFirst) {
+ memset(data, 0, sizeof data);
+ for (k=0; k<sizeof data && glyphs < end; k++, glyphs++)
+ for (j=0; j<8; j++)
+ data[k] |= ((*glyphs>>(7-j))&1)<<j;
+ } else g = (void *)f->glyphs;
+
+ p->glyph_cache[i] = XCreatePixmap(p->display,
+ DefaultRootWindow(p->display),
+ d->cell_w, d->cell_h * 1024, 1);
+
+ gc = XCreateGC(p->display, p->glyph_cache[i], 0, &values);
+ XSetForeground(p->display, gc, WhitePixel(p->display, p->screen));
+ XSetBackground(p->display, gc, BlackPixel(p->display, p->screen));
+ XMatchVisualInfo(p->display, p->screen, 1, StaticGray, &vi);
+
+ image = XCreateImage(p->display,
+ vi.visual, 1, XYBitmap, (-d->cell_w)&7, g,
+ d->cell_w, d->cell_h * 1024, 8, 0);
+ XPutImage(p->display, p->glyph_cache[i], gc, image,
+ 0, 0, 0, 0, d->cell_w, d->cell_h * 1024);
+
+ //XDestroyImage(image);
+ XFreeGC(p->display, gc);
+ }
+
+ for (i=0; i<16; i++) {
+ XColor color;
+ int R = 0x55 * (i&1);
+ int G = 0x55 * (i&2) >> 1;
+ int B = 0x55 * (i&4) >> 2;
+ if (i&8) {
+ R += R + 0x55;
+ G += G + 0x55;
+ B += B + 0x55;
+ } else if (i == 7) R = G = B = 0xAA;
+ color.red = R<<8;
+ color.green = G<<8;
+ color.blue = B<<8;
+ XAllocColor(p->display, DefaultColormap(p->display, p->screen), &color);
+ p->colors[i] = color.pixel;
+ }
+
+ return 0;
+error:
+ return -1;
+}
+
+int uudisp_fd_set(struct uudisp *d, int tty, void *fds)
+{
+ struct priv *p = (struct priv *)&d->priv;
+ FD_SET(p->fd, (fd_set *)fds);
+ return p->fd > tty ? p->fd+1 : tty+1;
+}
+
+struct
+{
+ KeySym ks;
+ char s[7], l;
+} keys[] = {
+ { XK_Home, "\033[1~",4 },
+ { XK_Insert, "\033[2~",4 },
+ { XK_Delete, "\033[3~",4 },
+ { XK_End, "\033[4~",4 },
+ { XK_Page_Up, "\033[5~",4 },
+ { XK_Page_Down, "\033[6~",4 },
+ { XK_Up, "\033[A",3 },
+ { XK_Down, "\033[B",3 },
+ { XK_Right, "\033[C",3 },
+ { XK_Left, "\033[D",3 },
+ { XK_F1, "\033[[A",4 },
+ { XK_F2, "\033[[B",4 },
+ { XK_F3, "\033[[C",4 },
+ { XK_F4, "\033[[D",4 },
+ { XK_F5, "\033[[E",4 },
+ { XK_F6, "\033[17~",5 },
+ { XK_F7, "\033[18~",5 },
+ { XK_F8, "\033[19~",5 },
+ { XK_F9, "\033[20~",5 },
+ { XK_F10, "\033[21~",5 },
+ { XK_F11, "\033[23~",5 },
+ { XK_F12, "\033[24~",5 },
+ { 0, "" }
+};
+
+void uudisp_next_event(struct uudisp *d, void *fds)
+{
+ struct priv *p = (struct priv *)&d->priv;
+ unsigned char b;
+ XEvent ev;
+ KeySym ks;
+ size_t r, l = sizeof(d->inbuf);
+ unsigned char *s = d->inbuf;
+ char tmp[32], mbtmp[sizeof(tmp)*MB_LEN_MAX];
+ wchar_t wtmp[sizeof(tmp)];
+ int i, n;
+ int y1, y2;
+
+ d->inlen = 0;
+ d->intext = d->inbuf;
+
+ if (!FD_ISSET(p->fd, (fd_set *)fds)) return;
+
+ while (XPending(p->display)) {
+ XNextEvent(p->display, &ev);
+ switch (ev.type) {
+ case Expose:
+ y1 = ev.xexpose.y / d->cell_h;
+ y2 = y1 + ev.xexpose.height / d->cell_h + 1;
+ for (i=0; i<d->h; i++)
+ if ((unsigned)p->slices_y[i]-y1 <= y2-y1)
+ p->slices_y[i] = -1;
+ break;
+ case KeyPress:
+#if 0
+ // r = XmbLookupString(p->ic, (void *)&ev, s, l, &ks, &status);
+ switch(status) {
+ case XLookupChars:
+ case XLookupBoth:
+ //
+ }
+#endif
+ r = XLookupString((void *)&ev, tmp, sizeof(tmp), &ks, 0);
+ if (r>=sizeof(tmp)) continue;
+ if ((ev.xkey.state & Mod1Mask) && l) {
+ *s++ = '\033';
+ l--;
+ }
+ for (i=0; keys[i].ks && keys[i].ks != ks; i++);
+ if (keys[i].ks) {
+ if (keys[i].l > l) continue;
+ memcpy(s, keys[i].s, keys[i].l);
+ s += keys[i].l;
+ l -= keys[i].l;
+ continue;
+ }
+ if ((ev.xkey.state & ControlMask) && ks == XK_minus && l) {
+ *s++ = '_' & 0x1f;
+ l--;
+ continue;
+ }
+ if ((ev.xkey.state & ControlMask) && (ks == XK_2 || ks == XK_space) && l) {
+ *s++ = 0;
+ l--;
+ continue;
+ }
+ if (!r) continue;
+
+ /* Deal with Latin-1 crap.. */
+ for (i=0; i<=r; i++) wtmp[i] = tmp[i];
+ r = wcstombs(mbtmp, wtmp, sizeof mbtmp);
+ if ((int)r > 0 && r <= l) {
+ memcpy(s, mbtmp, r);
+ s += r;
+ l -= r;
+ }
+ break;
+ }
+ }
+ d->inlen = s - d->inbuf;
+}
+
+void uudisp_close(struct uudisp *d)
+{
+ struct priv *p = (struct priv *)&d->priv;
+ XCloseDisplay(p->display);
+}
+
+
+
+void uudisp_draw_glyph(struct uudisp *d, int idx, int x, const void *glyph)
+{
+ struct priv *p = (void *)&d->priv;
+ struct ucf *f = d->font;
+ const unsigned char *foo = glyph;
+ int g = (foo-f->glyphs)/f->S;
+ int gp = g >> 10;
+ g &= 1023;
+
+ XCopyPlane(p->display, p->glyph_cache[gp], p->pixmap, p->maskgc,
+ 0, g*d->cell_h, d->cell_w, d->cell_h,
+ x * d->cell_w, idx * d->cell_h, 1);
+ XCopyPlane(p->display, p->glyph_cache[gp], p->pixmap, p->fggc,
+ 0, g*d->cell_h, d->cell_w, d->cell_h,
+ x * d->cell_w, idx * d->cell_h, 1);
+}
+
+void uudisp_predraw_cell(struct uudisp *d, int idx, int x, int color)
+{
+ struct priv *p = (void *)&d->priv;
+ XSetForeground(p->display, p->fggc, p->colors[color&15]);
+ XSetForeground(p->display, p->bggc, p->colors[color>>4]);
+ XFillRectangle(p->display, p->pixmap, p->bggc,
+ x*d->cell_w, idx*d->cell_h, d->cell_w, d->cell_h);
+}
+
+static void blit_slice(struct uudisp *d, int idx, int x1, int x2)
+{
+ struct priv *p = (void *)&d->priv;
+
+ XCopyArea(p->display, p->pixmap, p->window, p->wingc,
+ x1*d->cell_w, idx*d->cell_h,
+ (x2-x1+1)*d->cell_w, d->cell_h,
+ x1*d->cell_w, p->slices_y[idx]*d->cell_h);
+}
+
+void uudisp_refresh(struct uudisp *d, struct uuterm *t)
+{
+ struct priv *p = (void *)&d->priv;
+ int h = t->h < d->h ? t->h : d->h;
+ int x1, x2, idx, y;
+
+ /* Clean up cursor first.. */
+ if (p->curs_on && (!(d->blink&1) || t->x != p->curs_x || t->y != p->curs_y)) {
+ idx = t->rows[p->curs_y]->idx;
+ if ((unsigned)p->slices_y[idx] < d->h)
+ blit_slice(d, idx, p->curs_x, p->curs_x);
+ p->curs_on = 0;
+ }
+
+ for (y=0; y<h; y++) {
+ x1 = t->rows[y]->x1;
+ x2 = t->rows[y]->x2;
+ idx = t->rows[y]->idx;
+ if (x2 >= x1) {
+ uuterm_refresh_row(d, t->rows[y], x1, x2);
+ t->rows[y]->x1 = t->w;
+ t->rows[y]->x2 = -1;
+ }
+ if (p->slices_y[idx] != y) {
+ p->slices_y[idx] = y;
+ x1 = 0;
+ x2 = d->w-1;
+ } else if (x2 < x1) continue;
+ blit_slice(d, idx, x1, x2);
+ }
+ p->curs_x = t->x;
+ p->curs_y = t->y;
+ if ((d->blink & 1) && !p->curs_on)
+ XFillRectangle(p->display, p->window, p->cugc,
+ p->curs_x*d->cell_w, p->curs_y*d->cell_h,
+ d->cell_w, d->cell_h);
+ p->curs_on = (d->blink & 1);
+ XFlush(p->display);
+}