X-Git-Url: https://git.danieliu.xyz/?p=st.git;a=blobdiff_plain;f=x.c;h=865dacc83b23cd467d6f9dc02bb7d9f3c2e82463;hp=873ff08bb84184a438258cd3ff7b99bcff5515fd;hb=e85b6b64660214121164ea97fb098eaa4935f7db;hpb=a3beb626d2dae9d4d0883c7c8cb6ba58b0609105 diff --git a/x.c b/x.c index 873ff08..865dacc 100644 --- a/x.c +++ b/x.c @@ -1,15 +1,15 @@ /* See LICENSE for license details. */ #include +#include +#include #include #include -#include #include #include #include #include #include #include -#include #include #include #include @@ -75,6 +75,15 @@ typedef XftColor Color; typedef XftGlyphFontSpec GlyphFontSpec; /* Purely graphic info */ +typedef struct { + int tw, th; /* tty width and height */ + int w, h; /* window width and height */ + int ch; /* char height */ + int cw; /* char width */ + int mode; /* window state/mode flags */ + int cursor; /* cursor style */ +} TermWindow; + typedef struct { Display *dpy; Colormap cmap; @@ -130,17 +139,22 @@ static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int); static void xdrawglyph(Glyph, int, int); static void xclear(int, int, int, int); static int xgeommasktogravity(int); +static void ximopen(Display *); +static void ximinstantiate(Display *, XPointer, XPointer); +static void ximdestroy(XIM, XPointer, XPointer); static void xinit(int, int); static void cresize(int, int); static void xresize(int, int); +static void xhints(void); +static int xloadcolor(int, const char *, Color *); static int xloadfont(Font *, FcPattern *); static void xloadfonts(char *, double); static void xunloadfont(Font *); static void xunloadfonts(void); static void xsetenv(void); static void xseturgency(int); -static int x2col(int); -static int y2row(int); +static int evcol(XEvent *); +static int evrow(XEvent *); static void expose(XEvent *); static void visibility(XEvent *); @@ -227,13 +241,15 @@ static char *opt_line = NULL; static char *opt_name = NULL; static char *opt_title = NULL; +static int oldbutton = 3; /* button event on startup: 3 = release */ + void clipcopy(const Arg *dummy) { Atom clipboard; - if (xsel.clipboard != NULL) - free(xsel.clipboard); + free(xsel.clipboard); + xsel.clipboard = NULL; if (xsel.primary != NULL) { xsel.clipboard = xstrdup(xsel.primary); @@ -296,17 +312,17 @@ zoomreset(const Arg *arg) } int -x2col(int x) +evcol(XEvent *e) { - x -= borderpx; + int x = e->xbutton.x - borderpx; LIMIT(x, 0, win.tw - 1); return x / win.cw; } int -y2row(int y) +evrow(XEvent *e) { - y -= borderpx; + int y = e->xbutton.y - borderpx; LIMIT(y, 0, win.th - 1); return y / win.ch; } @@ -323,7 +339,7 @@ mousesel(XEvent *e, int done) break; } } - selextend(x2col(e->xbutton.x), y2row(e->xbutton.y), seltype, done); + selextend(evcol(e), evrow(e), seltype, done); if (done) setsel(getsel(), e->xbutton.time); } @@ -331,9 +347,8 @@ mousesel(XEvent *e, int done) void mousereport(XEvent *e) { - int x = x2col(e->xbutton.x), y = y2row(e->xbutton.y), - button = e->xbutton.button, state = e->xbutton.state, - len; + int len, x = evcol(e), y = evrow(e), + button = e->xbutton.button, state = e->xbutton.state; char buf[40]; static int ox, oy; @@ -428,7 +443,7 @@ bpress(XEvent *e) xsel.tclick2 = xsel.tclick1; xsel.tclick1 = now; - selstart(x2col(e->xbutton.x), y2row(e->xbutton.y), snap); + selstart(evcol(e), evrow(e), snap); } } @@ -452,18 +467,16 @@ selnotify(XEvent *e) ulong nitems, ofs, rem; int format; uchar *data, *last, *repl; - Atom type, incratom, property; + Atom type, incratom, property = None; incratom = XInternAtom(xw.dpy, "INCR", 0); ofs = 0; - if (e->type == SelectionNotify) { + if (e->type == SelectionNotify) property = e->xselection.property; - } else if(e->type == PropertyNotify) { + else if (e->type == PropertyNotify) property = e->xproperty.atom; - } else { - return; - } + if (property == None) return; @@ -608,12 +621,15 @@ selrequest(XEvent *e) void setsel(char *str, Time t) { + if (!str) + return; + free(xsel.primary); xsel.primary = str; XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t); if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win) - selclear_(NULL); + selclear(); } void @@ -659,6 +675,8 @@ cresize(int width, int height) col = (win.w - 2 * borderpx) / win.cw; row = (win.h - 2 * borderpx) / win.ch; + col = MAX(1, col); + row = MAX(1, row); tresize(col, row); xresize(col, row); @@ -668,8 +686,8 @@ cresize(int width, int height) void xresize(int col, int row) { - win.tw = MAX(1, col * win.cw); - win.th = MAX(1, row * win.ch); + win.tw = col * win.cw; + win.th = row * win.ch; XFreePixmap(xw.dpy, xw.buf); xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, @@ -718,20 +736,20 @@ xloadcols(void) static int loaded; Color *cp; - dc.collen = MAX(LEN(colorname), 256); - dc.col = xmalloc(dc.collen * sizeof(Color)); - if (loaded) { for (cp = dc.col; cp < &dc.col[dc.collen]; ++cp) XftColorFree(xw.dpy, xw.vis, xw.cmap, cp); + } else { + dc.collen = MAX(LEN(colorname), 256); + dc.col = xmalloc(dc.collen * sizeof(Color)); } for (i = 0; i < dc.collen; i++) if (!xloadcolor(i, NULL, &dc.col[i])) { if (colorname[i]) - die("Could not allocate color '%s'\n", colorname[i]); + die("could not allocate color '%s'\n", colorname[i]); else - die("Could not allocate color %d\n", i); + die("could not allocate color %d\n", i); } loaded = 1; } @@ -771,19 +789,21 @@ xhints(void) XClassHint class = {opt_name ? opt_name : termname, opt_class ? opt_class : termname}; XWMHints wm = {.flags = InputHint, .input = 1}; - XSizeHints *sizeh = NULL; + XSizeHints *sizeh; sizeh = XAllocSizeHints(); - sizeh->flags = PSize | PResizeInc | PBaseSize; + sizeh->flags = PSize | PResizeInc | PBaseSize | PMinSize; sizeh->height = win.h; sizeh->width = win.w; sizeh->height_inc = win.ch; sizeh->width_inc = win.cw; sizeh->base_height = 2 * borderpx; sizeh->base_width = 2 * borderpx; + sizeh->min_height = win.ch + 2 * borderpx; + sizeh->min_width = win.cw + 2 * borderpx; if (xw.isfixed) { - sizeh->flags |= PMaxSize | PMinSize; + sizeh->flags |= PMaxSize; sizeh->min_width = sizeh->max_width = win.w; sizeh->min_height = sizeh->max_height = win.h; } @@ -856,7 +876,7 @@ xloadfont(Font *f, FcPattern *pattern) if ((XftPatternGetInteger(f->match->pattern, "slant", 0, &haveattr) != XftResultMatch) || haveattr < wantattr) { f->badslant = 1; - fputs("st: font slant does not match\n", stderr); + fputs("font slant does not match\n", stderr); } } @@ -865,7 +885,7 @@ xloadfont(Font *f, FcPattern *pattern) if ((XftPatternGetInteger(f->match->pattern, "weight", 0, &haveattr) != XftResultMatch) || haveattr != wantattr) { f->badweight = 1; - fputs("st: font weight does not match\n", stderr); + fputs("font weight does not match\n", stderr); } } @@ -892,16 +912,14 @@ xloadfonts(char *fontstr, double fontsize) { FcPattern *pattern; double fontval; - float ceilf(float); - if (fontstr[0] == '-') { + if (fontstr[0] == '-') pattern = XftXlfdParse(fontstr, False, False); - } else { + else pattern = FcNameParse((FcChar8 *)fontstr); - } if (!pattern) - die("st: can't open font %s\n", fontstr); + die("can't open font %s\n", fontstr); if (fontsize > 1) { FcPatternDel(pattern, FC_PIXEL_SIZE); @@ -927,7 +945,7 @@ xloadfonts(char *fontstr, double fontsize) } if (xloadfont(&dc.font, pattern)) - die("st: can't open font %s\n", fontstr); + die("can't open font %s\n", fontstr); if (usedfontsize < 0) { FcPatternGetDouble(dc.font.match->pattern, @@ -944,17 +962,17 @@ xloadfonts(char *fontstr, double fontsize) FcPatternDel(pattern, FC_SLANT); FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); if (xloadfont(&dc.ifont, pattern)) - die("st: can't open font %s\n", fontstr); + die("can't open font %s\n", fontstr); FcPatternDel(pattern, FC_WEIGHT); FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD); if (xloadfont(&dc.ibfont, pattern)) - die("st: can't open font %s\n", fontstr); + die("can't open font %s\n", fontstr); FcPatternDel(pattern, FC_SLANT); FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN); if (xloadfont(&dc.bfont, pattern)) - die("st: can't open font %s\n", fontstr); + die("can't open font %s\n", fontstr); FcPatternDestroy(pattern); } @@ -981,6 +999,43 @@ xunloadfonts(void) xunloadfont(&dc.ibfont); } +void +ximopen(Display *dpy) +{ + XIMCallback destroy = { .client_data = NULL, .callback = ximdestroy }; + + if ((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) { + XSetLocaleModifiers("@im=local"); + if ((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) { + XSetLocaleModifiers("@im="); + if ((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) + die("XOpenIM failed. Could not open input device.\n"); + } + } + if (XSetIMValues(xw.xim, XNDestroyCallback, &destroy, NULL) != NULL) + die("XSetIMValues failed. Could not set input method value.\n"); + xw.xic = XCreateIC(xw.xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, + XNClientWindow, xw.win, XNFocusWindow, xw.win, NULL); + if (xw.xic == NULL) + die("XCreateIC failed. Could not obtain input method.\n"); +} + +void +ximinstantiate(Display *dpy, XPointer client, XPointer call) +{ + ximopen(dpy); + XUnregisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL, + ximinstantiate, NULL); +} + +void +ximdestroy(XIM xim, XPointer client, XPointer call) +{ + xw.xim = NULL; + XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL, + ximinstantiate, NULL); +} + void xinit(int cols, int rows) { @@ -991,13 +1046,13 @@ xinit(int cols, int rows) XColor xmousefg, xmousebg; if (!(xw.dpy = XOpenDisplay(NULL))) - die("Can't open display\n"); + die("can't open display\n"); xw.scr = XDefaultScreen(xw.dpy); xw.vis = XDefaultVisual(xw.dpy, xw.scr); /* font */ if (!FcInit()) - die("Could not init fontconfig.\n"); + die("could not init fontconfig.\n"); usedfont = (opt_font == NULL)? font : opt_font; xloadfonts(usedfont, 0); @@ -1018,7 +1073,7 @@ xinit(int cols, int rows) xw.attrs.background_pixel = dc.col[defaultbg].pixel; xw.attrs.border_pixel = dc.col[defaultbg].pixel; xw.attrs.bit_gravity = NorthWestGravity; - xw.attrs.event_mask = FocusChangeMask | KeyPressMask + xw.attrs.event_mask = FocusChangeMask | KeyPressMask | KeyReleaseMask | ExposureMask | VisibilityChangeMask | StructureNotifyMask | ButtonMotionMask | ButtonPressMask | ButtonReleaseMask; xw.attrs.colormap = xw.cmap; @@ -1046,22 +1101,7 @@ xinit(int cols, int rows) xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap); /* input methods */ - if ((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) { - XSetLocaleModifiers("@im=local"); - if ((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) { - XSetLocaleModifiers("@im="); - if ((xw.xim = XOpenIM(xw.dpy, - NULL, NULL, NULL)) == NULL) { - die("XOpenIM failed. Could not open input" - " device.\n"); - } - } - } - xw.xic = XCreateIC(xw.xim, XNInputStyle, XIMPreeditNothing - | XIMStatusNothing, XNClientWindow, xw.win, - XNFocusWindow, xw.win, NULL); - if (xw.xic == NULL) - die("XCreateIC failed. Could not obtain input method.\n"); + ximopen(xw.dpy); /* white cursor, black outline */ cursor = XCreateFontCursor(xw.dpy, mouseshape); @@ -1395,12 +1435,13 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) og.mode ^= ATTR_REVERSE; xdrawglyph(og, ox, oy); + if (IS_SET(MODE_HIDE)) + return; + /* * Select the right color for the right mode. */ g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE; - g.fg = defaultbg; - g.bg = defaultcs; if (IS_SET(MODE_REVERSE)) { g.mode |= ATTR_REVERSE; @@ -1414,22 +1455,20 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og) } } else { if (selected(cx, cy)) { - drawcol = dc.col[defaultrcs]; g.fg = defaultfg; g.bg = defaultrcs; } else { - drawcol = dc.col[defaultcs]; + g.fg = defaultbg; + g.bg = defaultcs; } + drawcol = dc.col[g.bg]; } - if (IS_SET(MODE_HIDE)) - return; - /* draw the new one */ if (IS_SET(MODE_FOCUSED)) { switch (win.cursor) { - case 7: /* st extension: snowman */ - utf8decode("☃", &g.u, UTF_SIZ); + case 7: /* st extension: snowman (U+2603) */ + g.u = 0x2603; case 0: /* Blinking Block */ case 1: /* Blinking Block (Default) */ case 2: /* Steady Block */ @@ -1484,7 +1523,7 @@ void xsettitle(char *p) { XTextProperty prop; - DEFAULT(p, "st"); + DEFAULT(p, opt_title); Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle, &prop); @@ -1540,6 +1579,16 @@ xfinishdraw(void) defaultfg : defaultbg].pixel); } +void +xximspot(int x, int y) +{ + XPoint spot = { borderpx + x * win.cw, borderpx + (y + 1) * win.ch }; + XVaNestedList attr = XVaCreateNestedList(0, XNSpotLocation, &spot, NULL); + + XSetICValues(xw.xic, XNPreeditAttributes, attr, NULL); + XFree(attr); +} + void expose(XEvent *ev) { @@ -1733,8 +1782,7 @@ cmessage(XEvent *e) win.mode &= ~MODE_FOCUSED; } } else if (e->xclient.data.l[0] == xw.wmdeletewin) { - /* Send SIGHUP to shell */ - kill(pid, SIGHUP); + ttyhangup(); exit(0); } } @@ -1755,6 +1803,7 @@ run(void) int w = win.w, h = win.h; fd_set rfd; int xfd = XConnectionNumber(xw.dpy), xev, blinkset = 0, dodraw = 0; + int ttyfd; struct timespec drawtimeout, *tv = NULL, now, last, lastblink; long deltatime; @@ -1774,7 +1823,7 @@ run(void) } } while (ev.type != MapNotify); - ttynew(opt_line, opt_io, opt_cmd); + ttyfd = ttynew(opt_line, shell, opt_io, opt_cmd); cresize(w, h); clock_gettime(CLOCK_MONOTONIC, &last); @@ -1782,15 +1831,15 @@ run(void) for (xev = actionfps;;) { FD_ZERO(&rfd); - FD_SET(cmdfd, &rfd); + FD_SET(ttyfd, &rfd); FD_SET(xfd, &rfd); - if (pselect(MAX(xfd, cmdfd)+1, &rfd, NULL, NULL, tv, NULL) < 0) { + if (pselect(MAX(xfd, ttyfd)+1, &rfd, NULL, NULL, tv, NULL) < 0) { if (errno == EINTR) continue; die("select failed: %s\n", strerror(errno)); } - if (FD_ISSET(cmdfd, &rfd)) { + if (FD_ISSET(ttyfd, &rfd)) { ttyread(); if (blinktimeout) { blinkset = tattrset(ATTR_BLINK); @@ -1834,7 +1883,7 @@ run(void) if (xev && !FD_ISSET(xfd, &rfd)) xev--; - if (!FD_ISSET(cmdfd, &rfd) && !FD_ISSET(xfd, &rfd)) { + if (!FD_ISSET(ttyfd, &rfd) && !FD_ISSET(xfd, &rfd)) { if (blinkset) { if (TIMEDIFF(now, lastblink) \ > blinktimeout) { @@ -1914,19 +1963,19 @@ main(int argc, char *argv[]) opt_embed = EARGF(usage()); break; case 'v': - die("%s " VERSION " (c) 2010-2016 st engineers\n", argv0); + die("%s " VERSION "\n", argv0); break; default: usage(); } ARGEND; run: - if (argc > 0) { - /* eat all remaining arguments */ + if (argc > 0) /* eat all remaining arguments */ opt_cmd = argv; - if (!opt_title && !opt_line) - opt_title = basename(xstrdup(argv[0])); - } + + if (!opt_title) + opt_title = (opt_line || !opt_cmd) ? "st" : opt_cmd[0]; + setlocale(LC_CTYPE, ""); XSetLocaleModifiers(""); cols = MAX(cols, 1);