diff --git a/.gitignore b/.gitignore index 8068c9a..9d8af76 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,3 @@ st *.rej *.orig -src/ -pkg/ -*.tar* diff --git a/.woodpecker.yml b/.woodpecker.yml deleted file mode 100644 index 6d2e6e8..0000000 --- a/.woodpecker.yml +++ /dev/null @@ -1,45 +0,0 @@ -matrix: - # PLATFORM: - # - linux/amd64 - # - linux/arm64 - - ARCH: - # tuur - - tigerlake - # cenny - - skylake - -branches: master -platform: linux/amd64 - -when: - event: push - -pipeline: - build: - image: 'menci/archlinuxarm:base-devel' - commands: - # Add my bur repo to pacman for the libxft-bgra dependency - - echo -e '[bur]\nServer = https://arch.r8r.be/$repo/$arch\nSigLevel = Optional' >> /etc/pacman.conf - # Update packages - - pacman -Syu --noconfirm - # Create non-root user to perform build & switch to their home - - groupadd -g 1000 builder - - useradd -mg builder builder - - chown -R builder:builder "$PWD" - - "echo 'builder ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers" - - su builder - # Build the package - - > - MAKEFLAGS="-j$(nproc)" - makepkg -s --noconfirm --needed - CFLAGS+=" -O3 -flto -march=${ARCH} -mtune=${ARCH}" - CARCH="x86_64_${ARCH}" - - publish: - image: 'curlimages/curl' - commands: - # Publish the package - - 'curl --fail -s -XPOST -H "Authorization: Bearer $API_KEY" -T "$(ls *.pkg*)" https://arch2.r8r.be/jjr' - secrets: - - api_key diff --git a/FAQ b/FAQ index 6287a27..0f9609d 100644 --- a/FAQ +++ b/FAQ @@ -29,8 +29,8 @@ you can manually run `tic -sx st.info`. ## I would like to have utmp and/or scroll functionality by default -You can add the absolute path of both programs in your config.h file. You only -have to modify the value of utmp and scroll variables. +You can add the absolute patch of both programs in your config.h +file. You only have to modify the value of utmp and scroll variables. ## Why doesn't the Del key work in some programs? @@ -248,6 +248,3 @@ fonts: Please don't bother reporting this bug to st, but notify the upstream Xft developers about fixing this bug. - -As of 2022-09-05 this now seems to be finally fixed in libXft 2.3.5: -https://gitlab.freedesktop.org/xorg/lib/libxft/-/blob/libXft-2.3.5/NEWS diff --git a/LICENSE b/LICENSE index 3cbf420..d80eb47 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT/X Consortium License -© 2014-2022 Hiltjo Posthuma +© 2014-2020 Hiltjo Posthuma © 2018 Devin J. Pohly © 2014-2017 Quentin Rameau © 2009-2012 Aurélien APTEL diff --git a/Makefile b/Makefile index d1fa877..2ffd3c8 100644 --- a/Makefile +++ b/Makefile @@ -49,7 +49,7 @@ install: st mkdir -p $(DESTDIR)$(MANPREFIX)/man1 sed "s/VERSION/$(VERSION)/g" < st.1 > $(DESTDIR)$(MANPREFIX)/man1/st.1 chmod 644 $(DESTDIR)$(MANPREFIX)/man1/st.1 - # tic -sx st.info + tic -sx st.info @echo Please see the README file regarding the terminfo entry of st. uninstall: diff --git a/PKGBUILD b/PKGBUILD deleted file mode 100644 index 8f1e4fa..0000000 --- a/PKGBUILD +++ /dev/null @@ -1,77 +0,0 @@ -# Maintainer: Jef Roosens - -pkgname=jjr-st -pkgver=0.9.2 -pkgrel=1 -pkgdesc="Chewing_Bever's personal build of the st terminal" - -url="https://git.rustybever.be/Chewing_Bever/st" -license=("MIT") -arch=( - "x86_64" - "x86_64_tigerlake" - "x86_64_skylake" - "aarch64" -) - -depends=("glibc" "libxft-bgra") -makedepends=("gcc") - -provides=("st") -conflicts=("st" "st-git") - -source=("arg.h" "boxdraw.c" "boxdraw_data.h" "config.def.h" "config.h" - "config.mk" "hb.c" "hb.h" "LICENSE" "Makefile" "st.1" "st.c" "st.h" "st.info" - "win.h" "x.c" "README") -sha256sums=('1a10fac42d03b3a1231cd6998a73fb4ab4f191694628953e7229f6de2053a985' - 'e8366b6b7840759157761b4d311028fa29b846f393b9e928a2587b3ac9bffdd1' - '808dbefe40e81b88da173985e1bd5c0a0d88d517b7cc1c6d68753e586ffe1698' - '49bff578b6c882123393c867689f4330d6ba7cfe85fe359ea7424b228b22970e' - '6fa7874b83e98a30e8c66c8f7d5539d1b2ec6c2267ef2c3945620826187b6b64' - '2ac9d7e18c87595165dffdcedc96c2355d74778667a0770e5079d740cb50ce0c' - 'f4fae0ee42168f492ea59825928d1dbaceae5cf9e6fe2f820a429a68266000c7' - '4a133d16a818379ab849b41c30cb4b4f989a00c9b1e96907a4d130d12c36a79e' - '5c25b701b4482ccc8d5ea0770e553ad8a8c5c87650df07543b3b3f9456726d54' - '20459f3d01ba1750c55764c0554a7aebcfad74f8f359c6cc30848c691483c2ef' - '5b0d65d135fcc3d51f60e4fe4d86c5bbd1331266f9b38ecfb86914668c03921c' - '24f5497597f2704e22ba58891c6a3502e391755eed5e8cbd7dfe875fef63b43c' - '285b883ebd0884467be95562885f4cf594cd72cf7b4925476538483fe4022f39' - '2eb2f15957b8132a2d25129c24bb97f64657bd821447f36ef2cf0526b42846e8' - 'c1f30d9d38828194c25fa943978a4ee766fe77294e98cea0e4fffa81756bddad' - 'ad0cfcd7242682a05421788163aefe45164005f7916cc29a4dc60c4d74005805' - 'f767c242485eb537f0df13cbcc182980d29152a6e25036cf65f334fb3ae8b29e') -sha512sums=('53846896087eee0242e3679e8f35be8330e5de63b0247876ac368cf13f62b03c564f99957d49c7f9a7b74cc5190a32b034955d7bf633cc2848da266d7a7f1786' - '031a4bcec190b6e8dbc64e604674f5b754ecc2a79d63f0bb1d9bfe7c79bcb17ee3f36440dd55580e5b238e5e4bf808aa0f0f65cf00072f47d8c9851df06e6489' - '19d9d5414d78d5cc59a080e7f9955e02420c1d18268299160cb4bcb156c6cb0d0cbcf16a9e20094b67cfba3b721a4bfb71223d772c37238a9390388b00eb8919' - '0dba6f78e020f6b51acbd5b19a1e6d62ce990fcbe5a0d5f49eca065cc5f4600dad1222be282c01daf08a213d16e45dcd96497ff686b1bc5cc5e8996b5cda9864' - 'bf0d3f0cbeb07b7268c8e08331cb3a82ee438d8414a62233a0accc3966ff96cc37da932ab17fda9a8d560446e4e2c931bd62af0c1e8eb84447ccf48774ee92db' - 'c5a6dda87f542378261327ae53f8c6c8ef9cc35575f10c51291d4b36fed47ced77bec7b136fbf2c678794501d34f35911f740ee2b50b30af2e52c9baf393407f' - 'd847eb005da53e8938379854017451fc716c15228ffccd7a75b75cbccb6259371ec233ddbdd5fefdacd28e0b5aaad41d163358732bdbefb9178678b637bf050c' - 'e287b76dfd1cb6930bdc3c74a77888b6f7e2309c24bf9466c65425418dcff8e977649c71a0ca0ce8c118901d4e81c3781f60324df8394ceee12dae9c7875dc02' - '60bda0e2668626949c4d70ce338c03ce8e2d0f98544ca7053f3061111506a3d8426357253982e56140bb005b6f3a3a383086d9b58a40d4dbd79a6bee9ec2677f' - '81259bdec9c42cbdffd12913672af141095b5c49be4c8d19951bd2a5dc4f2c525b7923579561c3259cb9b58d9f24b04d5e846ff4308a759c92e6eda12adb7b01' - '3e9378413277f344d46056e72c2cf19a3f68ed3175fcaa177a6a0c90d3ff6282d3cb423aa98d32fed9647d2be8cbd52b8adb6f73f87186e95d81320e90fc185d' - 'ce7d57550c1fd4731ec0adac11f2fcc6a163524bbdf72359ed544062226ce8775c5bb909e31f4bc92643442bd46be4061ade23d5dd356ad745bea9e59b8536d0' - 'c6f08ba53ea59c74b35f889a183feca2a124d46654a6f0556fb181c3843d7d11f9174a934ce01de630c46be2caf705c9ae636f3e59f9762079c3c821652cea87' - '683b40e8d7173ec8d84e2d53454e5111f2effce0c27641e010da1bcec7ee169bfad46142e01893b5e66df87f109bc1afeb944cbae5ce56aa55bfc2544d04e87a' - '28234c79599248929c85936c68ab68f977a722069c51424ae0faa92eddd5d4bf9fc75df0f4a509704ae5b56a2be13481883d675627c4e7fd47f6320a70d259ea' - '4cb372dd9b5711242bce1b82008f9b7c2cfae59c4d2f378df20a88134b61b050aa8f000b01e6e1c0195c14967111497974d67104c1895afb75065d2b6f461255' - 'd345c041854864ff8c21cbc5c934d3b5dda2fc7f97eee484d8cee4f3c8671ba5f2dcecad313a199e750a2d64d4e0dfbe9a6033d0ea701c1f9d9b6753502bf72b') - -build() { - make CFLAGS="$CFLAGS" -} - -package() { - local installopts='--mode 0644 -D --target-directory' - local shrdir="$pkgdir/usr/share" - local licdir="$shrdir/licenses/$pkgname" - local docdir="$shrdir/doc/$pkgname" - make PREFIX=/usr DESTDIR="$pkgdir" install - install $installopts "$licdir" "LICENSE" - install $installopts "$docdir" "README" - # install $installopts "$docdir" README.terminfo.rst - # install $installopts "$shrdir/$pkgname" "$_sourcedir/st.info" -} - -# vim: ft=bash diff --git a/config.def.h b/config.def.h index a723c27..f951881 100644 --- a/config.def.h +++ b/config.def.h @@ -162,10 +162,10 @@ static const char *altcolorname[] = { * Default colors (colorname index) * foreground, background, cursor, reverse cursor */ -unsigned int defaultfg = 258; -unsigned int defaultbg = 259; -unsigned int defaultcs = 256; -static unsigned int defaultrcs = 257; +unsigned int defaultfg = 12; +unsigned int defaultbg = 8; +static unsigned int defaultcs = 14; +static unsigned int defaultrcs = 15; /* * Default shape of cursor diff --git a/config.h b/config.h index fd6daba..2a7b8fb 100644 --- a/config.h +++ b/config.h @@ -5,12 +5,12 @@ * * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html */ -static char *font = "Fira Code:size=10:antialias=true;autohint=true"; +static char *font = "Fira Code:size=11:antialias=true;autohint=true"; static char *font2[] = { "Noto Color Emoji:size=10:antialias=true;autohint=true" }; -static int borderpx = 0; -float alpha = 0.7; +static int borderpx = 2; +float alpha = 0.95; /* Lines to move per scroll */ const unsigned int mousescrollincrement = 5; @@ -151,7 +151,7 @@ static const char *altcolorname[] = { */ unsigned int defaultfg = 12; unsigned int defaultbg = 8; -unsigned int defaultcs = 14; +static unsigned int defaultcs = 14; static unsigned int defaultrcs = 15; /* diff --git a/config.mk b/config.mk index c107a00..8adb05d 100644 --- a/config.mk +++ b/config.mk @@ -1,5 +1,5 @@ # st version -VERSION = 0.9.2 +VERSION = 0.8.4 # Customize below to fit your system @@ -24,16 +24,14 @@ LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender\ # flags STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 -CFLAGS = -O1 -STCFLAGS = $(INCS) $(STCPPFLAGS) $(CPPFLAGS) $(CFLAGS) -STLDFLAGS = $(LIBS) $(LDFLAGS) +STCFLAGS = $(INCS) $(STCPPFLAGS) $(CPPFLAGS) $(CFLAGS) +STLDFLAGS = $(LIBS) $(LDFLAGS) # OpenBSD: #CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 -D_BSD_SOURCE #LIBS = -L$(X11LIB) -lm -lX11 -lutil -lXft \ # `$(PKG_CONFIG) --libs fontconfig` \ # `$(PKG_CONFIG) --libs freetype2` -#MANPREFIX = ${PREFIX}/man # compiler and linker -CC = cc +# CC = c99 diff --git a/st.c b/st.c index e28228e..a9690e5 100644 --- a/st.c +++ b/st.c @@ -168,7 +168,6 @@ static void csidump(void); static void csihandle(void); static void csiparse(void); static void csireset(void); -static void osc_color_response(int, int, int); static int eschandle(uchar); static void strdump(void); static void strhandle(void); @@ -194,18 +193,18 @@ static void tputc(Rune); static void treset(void); static void tscrollup(int, int, int); static void tscrolldown(int, int, int); -static void tsetattr(const int *, int); -static void tsetchar(Rune, const Glyph *, int, int); +static void tsetattr(int *, int); +static void tsetchar(Rune, Glyph *, int, int); static void tsetdirt(int, int); static void tsetscroll(int, int); static void tswapscreen(void); -static void tsetmode(int, int, const int *, int); +static void tsetmode(int, int, int *, int); static int twrite(const char *, int, int); static void tfulldirt(void); static void tcontrolcode(uchar ); static void tdectest(char ); static void tdefutf8(char); -static int32_t tdefcolor(const int *, int *, int); +static int32_t tdefcolor(int *, int *, int); static void tdeftran(char); static void tstrsequence(uchar); @@ -234,10 +233,10 @@ static int iofd = 1; static int cmdfd; static pid_t pid; -static const uchar utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0}; -static const uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8}; -static const Rune utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000}; -static const Rune utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF}; +static uchar utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0}; +static uchar utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8}; +static Rune utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000}; +static Rune utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF}; ssize_t xwrite(int fd, const char *s, size_t len) @@ -277,14 +276,12 @@ xrealloc(void *p, size_t len) } char * -xstrdup(const char *s) +xstrdup(char *s) { - char *p; - - if ((p = strdup(s)) == NULL) + if ((s = strdup(s)) == NULL) die("strdup: %s\n", strerror(errno)); - return p; + return s; } size_t @@ -357,10 +354,25 @@ utf8validate(Rune *u, size_t i) return i; } +static const char base64_digits[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, + 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, -1, 0, 0, 0, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, + 22, 23, 24, 25, 0, 0, 0, 0, 0, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + char base64dec_getc(const char **src) { - while (**src && !isprint((unsigned char)**src)) + while (**src && !isprint(**src)) (*src)++; return **src ? *((*src)++) : '='; /* emulate padding if string ends */ } @@ -370,13 +382,6 @@ base64dec(const char *src) { size_t in_len = strlen(src); char *result, *dst; - static const char base64_digits[256] = { - [43] = 62, 0, 0, 0, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, - 0, 0, 0, -1, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, - 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, - 0, 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 - }; if (in_len % 4) in_len += 4 - (in_len % 4); @@ -520,7 +525,7 @@ selsnap(int *x, int *y, int direction) { int newx, newy, xt, yt; int delim, prevdelim; - const Glyph *gp, *prevgp; + Glyph *gp, *prevgp; switch (sel.snap) { case SNAP_WORD: @@ -593,7 +598,7 @@ getsel(void) { char *str, *ptr; int y, bufsize, lastx, linelen; - const Glyph *gp, *last; + Glyph *gp, *last; if (sel.ob.x == -1) return NULL; @@ -760,7 +765,7 @@ stty(char **args) } int -ttynew(const char *line, char *cmd, const char *out, char **args) +ttynew(char *line, char *cmd, char *out, char **args) { int m, s; @@ -793,15 +798,14 @@ ttynew(const char *line, char *cmd, const char *out, char **args) break; case 0: close(iofd); - close(m); setsid(); /* create a new process group */ dup2(s, 0); dup2(s, 1); dup2(s, 2); if (ioctl(s, TIOCSCTTY, NULL) < 0) die("ioctl TIOCSCTTY failed: %s\n", strerror(errno)); - if (s > 2) - close(s); + close(s); + close(m); #ifdef __OpenBSD__ if (pledge("stdio getpw proc exec", NULL) == -1) die("pledge\n"); @@ -949,7 +953,7 @@ ttyresize(int tw, int th) } void -ttyhangup(void) +ttyhangup() { /* Send SIGHUP to shell */ kill(pid, SIGHUP); @@ -1249,9 +1253,9 @@ tmoveto(int x, int y) } void -tsetchar(Rune u, const Glyph *attr, int x, int y) +tsetchar(Rune u, Glyph *attr, int x, int y) { - static const char *vt100_0[62] = { /* 0x41 - 0x7e */ + static char *vt100_0[62] = { /* 0x41 - 0x7e */ "↑", "↓", "→", "←", "█", "▚", "☃", /* A - G */ 0, 0, 0, 0, 0, 0, 0, 0, /* H - O */ 0, 0, 0, 0, 0, 0, 0, 0, /* P - W */ @@ -1366,7 +1370,7 @@ tdeleteline(int n) } int32_t -tdefcolor(const int *attr, int *npar, int l) +tdefcolor(int *attr, int *npar, int l) { int32_t idx = -1; uint r, g, b; @@ -1416,7 +1420,7 @@ tdefcolor(const int *attr, int *npar, int l) } void -tsetattr(const int *attr, int l) +tsetattr(int *attr, int l) { int i; int32_t idx; @@ -1534,9 +1538,9 @@ tsetscroll(int t, int b) } void -tsetmode(int priv, int set, const int *args, int narg) +tsetmode(int priv, int set, int *args, int narg) { - int alt; const int *lim; + int alt, *lim; for (lim = args + narg; args < lim; ++args) { if (priv) { @@ -1839,18 +1843,11 @@ csihandle(void) case 'm': /* SGR -- Terminal attribute (color) */ tsetattr(csiescseq.arg, csiescseq.narg); break; - case 'n': /* DSR -- Device Status Report */ - switch (csiescseq.arg[0]) { - case 5: /* Status Report "OK" `0n` */ - ttywrite("\033[0n", sizeof("\033[0n") - 1, 0); - break; - case 6: /* Report Cursor Position (CPR) ";R" */ + case 'n': /* DSR – Device Status Report (cursor position) */ + if (csiescseq.arg[0] == 6) { len = snprintf(buf, sizeof(buf), "\033[%i;%iR", - term.c.y+1, term.c.x+1); + term.c.y+1, term.c.x+1); ttywrite(buf, len, 0); - break; - default: - goto unknown; } break; case 'r': /* DECSTBM -- Set Scrolling Region */ @@ -1912,41 +1909,11 @@ csireset(void) memset(&csiescseq, 0, sizeof(csiescseq)); } -void -osc_color_response(int num, int index, int is_osc4) -{ - int n; - char buf[32]; - unsigned char r, g, b; - - if (xgetcolor(is_osc4 ? num : index, &r, &g, &b)) { - fprintf(stderr, "erresc: failed to fetch %s color %d\n", - is_osc4 ? "osc4" : "osc", - is_osc4 ? num : index); - return; - } - - n = snprintf(buf, sizeof buf, "\033]%s%d;rgb:%02x%02x/%02x%02x/%02x%02x\007", - is_osc4 ? "4;" : "", num, r, r, g, g, b, b); - if (n < 0 || n >= sizeof(buf)) { - fprintf(stderr, "error: %s while printing %s response\n", - n < 0 ? "snprintf failed" : "truncation occurred", - is_osc4 ? "osc4" : "osc"); - } else { - ttywrite(buf, n, 1); - } -} - void strhandle(void) { char *p = NULL, *dec; int j, narg, par; - const struct { int idx; char *str; } osc_table[] = { - { defaultfg, "foreground" }, - { defaultbg, "background" }, - { defaultcs, "cursor" } - }; term.esc &= ~(ESC_STR_END|ESC_STR); strparse(); @@ -1956,15 +1923,7 @@ strhandle(void) case ']': /* OSC -- Operating System Command */ switch (par) { case 0: - if (narg > 1) { - xsettitle(strescseq.args[1]); - xseticontitle(strescseq.args[1]); - } - return; case 1: - if (narg > 1) - xseticontitle(strescseq.args[1]); - return; case 2: if (narg > 1) xsettitle(strescseq.args[1]); @@ -1980,39 +1939,16 @@ strhandle(void) } } return; - case 10: - case 11: - case 12: - if (narg < 2) - break; - p = strescseq.args[1]; - if ((j = par - 10) < 0 || j >= LEN(osc_table)) - break; /* shouldn't be possible */ - - if (!strcmp(p, "?")) { - osc_color_response(par, osc_table[j].idx, 0); - } else if (xsetcolorname(osc_table[j].idx, p)) { - fprintf(stderr, "erresc: invalid %s color: %s\n", - osc_table[j].str, p); - } else { - tfulldirt(); - } - return; case 4: /* color set */ if (narg < 3) break; p = strescseq.args[2]; /* FALLTHROUGH */ - case 104: /* color reset */ + case 104: /* color reset, here p = NULL */ j = (narg > 1) ? atoi(strescseq.args[1]) : -1; - - if (p && !strcmp(p, "?")) { - osc_color_response(j, 0, 1); - } else if (xsetcolorname(j, p)) { - if (par == 104 && narg <= 1) { - xloadcols(); + if (xsetcolorname(j, p)) { + if (par == 104 && narg <= 1) return; /* color reset without parameter */ - } fprintf(stderr, "erresc: invalid color j=%d, p=%s\n", j, p ? p : "(null)"); } else { @@ -2020,7 +1956,7 @@ strhandle(void) * TODO if defaultbg color is changed, borders * are dirty */ - tfulldirt(); + redraw(); } return; } @@ -2146,7 +2082,7 @@ void tdumpline(int n) { char buf[UTF_SIZ]; - const Glyph *bp, *end; + Glyph *bp, *end; bp = &term.line[n][0]; end = &bp[MIN(tlinelen(n), term.col) - 1]; @@ -2492,9 +2428,6 @@ check_control_code: * they must not cause conflicts with sequences. */ if (control) { - /* in UTF-8 mode ignore handling C1 control characters */ - if (IS_SET(MODE_UTF8) && ISCONTROLC1(u)) - return; tcontrolcode(u); /* * control codes are not shown ever @@ -2541,10 +2474,8 @@ check_control_code: gp = &term.line[term.c.y][term.c.x]; } - if (IS_SET(MODE_INSERT) && term.c.x+width < term.col) { + if (IS_SET(MODE_INSERT) && term.c.x+width < term.col) memmove(gp+width, gp, (term.col - term.c.x - width) * sizeof(Glyph)); - gp->mode &= ~ATTR_WIDE; - } if (term.c.x+width > term.col) { tnewline(1); @@ -2557,10 +2488,6 @@ check_control_code: if (width == 2) { gp->mode |= ATTR_WIDE; if (term.c.x+1 < term.col) { - if (gp[1].mode == ATTR_WIDE && term.c.x+2 < term.col) { - gp[2].u = ' '; - gp[2].mode &= ~ATTR_WDUMMY; - } gp[1].u = '\0'; gp[1].mode = ATTR_WDUMMY; } diff --git a/st.h b/st.h index 363cbb6..c961f90 100644 --- a/st.h +++ b/st.h @@ -97,7 +97,7 @@ void tnew(int, int); void tresize(int, int); void tsetdirtattr(int); void ttyhangup(void); -int ttynew(const char *, char *, const char *, char **); +int ttynew(char *, char *, char *, char **); size_t ttyread(void); void ttyresize(int, int); void ttywrite(const char *, size_t, int); @@ -115,7 +115,7 @@ size_t utf8encode(Rune, char *); void *xmalloc(size_t); void *xrealloc(void *, size_t); -char *xstrdup(const char *); +char *xstrdup(char *); int isboxdraw(Rune); ushort boxdrawindex(const Glyph *); @@ -140,4 +140,3 @@ extern unsigned int defaultfg; extern unsigned int defaultbg; extern const int boxdraw, boxdraw_bold, boxdraw_braille; extern float alpha; -extern unsigned int defaultcs; diff --git a/win.h b/win.h index 94679e4..bc0d180 100644 --- a/win.h +++ b/win.h @@ -30,8 +30,6 @@ void xdrawline(Line, int, int, int); void xfinishdraw(void); void xloadcols(void); int xsetcolorname(int, const char *); -int xgetcolor(int, unsigned char *, unsigned char *, unsigned char *); -void xseticontitle(char *); void xsettitle(char *); int xsetcursor(int); void xsetmode(int, unsigned int); diff --git a/x.c b/x.c index ed566c0..68f1d07 100644 --- a/x.c +++ b/x.c @@ -1,56 +1,56 @@ /* See LICENSE for license details. */ -#include -#include -#include -#include -#include -#include #include -#include +#include #include #include -#include #include #include #include #include +#include +#include +#include +#include +#include +#include +#include char *argv0; #include "arg.h" -#include "hb.h" #include "st.h" #include "win.h" +#include "hb.h" /* types used in config.h */ typedef struct { - uint mod; - KeySym keysym; - void (*func)(const Arg *); - const Arg arg; + uint mod; + KeySym keysym; + void (*func)(const Arg *); + const Arg arg; } Shortcut; typedef struct { - uint mod; - uint button; - void (*func)(const Arg *); - const Arg arg; - uint release; - int altscrn; /* 0: don't care, -1: not alt screen, 1: alt screen */ + uint mod; + uint button; + void (*func)(const Arg *); + const Arg arg; + uint release; + int altscrn; /* 0: don't care, -1: not alt screen, 1: alt screen */ } MouseShortcut; typedef struct { - KeySym k; - uint mask; - char *s; - /* three-valued logic variables: 0 indifferent, 1 on, -1 off */ - signed char appkey; /* application keypad */ - signed char appcursor; /* application cursor */ + KeySym k; + uint mask; + char *s; + /* three-valued logic variables: 0 indifferent, 1 on, -1 off */ + signed char appkey; /* application keypad */ + signed char appcursor; /* application cursor */ } Key; /* X modifiers */ -#define XK_ANY_MOD UINT_MAX -#define XK_NO_MOD 0 -#define XK_SWITCH_MOD (1 << 13 | 1 << 14) +#define XK_ANY_MOD UINT_MAX +#define XK_NO_MOD 0 +#define XK_SWITCH_MOD (1<<13) /* function definitions used in config.h */ static void clipcopy(const Arg *); @@ -67,14 +67,14 @@ static void ttysend(const Arg *); #include "config.h" /* XEMBED messages */ -#define XEMBED_FOCUS_IN 4 +#define XEMBED_FOCUS_IN 4 #define XEMBED_FOCUS_OUT 5 /* macros */ -#define IS_SET(flag) ((win.mode & (flag)) != 0) -#define TRUERED(x) (((x)&0xff0000) >> 8) -#define TRUEGREEN(x) (((x)&0xff00)) -#define TRUEBLUE(x) (((x)&0xff) << 8) +#define IS_SET(flag) ((win.mode & (flag)) != 0) +#define TRUERED(x) (((x) & 0xff0000) >> 8) +#define TRUEGREEN(x) (((x) & 0xff00)) +#define TRUEBLUE(x) (((x) & 0xff) << 8) typedef XftDraw *Draw; typedef XftColor Color; @@ -82,77 +82,76 @@ typedef XftGlyphFontSpec GlyphFontSpec; /* Purely graphic info */ typedef struct { - int tw, th; /* tty width and height */ - int w, h; /* window width and height */ - int hborderpx, vborderpx; - int ch; /* char height */ - int cw; /* char width */ - int mode; /* window state/mode flags */ - int cursor; /* cursor style */ + int tw, th; /* tty width and height */ + int w, h; /* window width and height */ + int hborderpx, vborderpx; + 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; - Window win; - Drawable buf; - GlyphFontSpec *specbuf; /* font spec buffer used for rendering */ - Atom xembed, wmdeletewin, netwmname, netwmiconname, netwmpid; - struct { - XIM xim; - XIC xic; - XPoint spot; - XVaNestedList spotlist; - } ime; - Draw draw; - Visual *vis; - XSetWindowAttributes attrs; - /* Here, we use the term *pointer* to differentiate the cursor - * one sees when hovering the mouse over the terminal from, e.g., - * a green rectangle where text would be entered. */ - Cursor vpointer, bpointer; /* visible and hidden pointers */ - int pointerisvisible; - int scr; - int isfixed; /* is fixed geometry? */ - int depth; /* bit depth */ - int l, t; /* left and top offset */ - int gm; /* geometry mask */ + Display *dpy; + Colormap cmap; + Window win; + Drawable buf; + GlyphFontSpec *specbuf; /* font spec buffer used for rendering */ + Atom xembed, wmdeletewin, netwmname, netwmpid; + struct { + XIM xim; + XIC xic; + XPoint spot; + XVaNestedList spotlist; + } ime; + Draw draw; + Visual *vis; + XSetWindowAttributes attrs; + /* Here, we use the term *pointer* to differentiate the cursor + * one sees when hovering the mouse over the terminal from, e.g., + * a green rectangle where text would be entered. */ + Cursor vpointer, bpointer; /* visible and hidden pointers */ + int pointerisvisible; + int scr; + int isfixed; /* is fixed geometry? */ + int depth; /* bit depth */ + int l, t; /* left and top offset */ + int gm; /* geometry mask */ } XWindow; typedef struct { - Atom xtarget; - char *primary, *clipboard; - struct timespec tclick1; - struct timespec tclick2; + Atom xtarget; + char *primary, *clipboard; + struct timespec tclick1; + struct timespec tclick2; } XSelection; /* Font structure */ #define Font Font_ typedef struct { - int height; - int width; - int ascent; - int descent; - int badslant; - int badweight; - short lbearing; - short rbearing; - XftFont *match; - FcFontSet *set; - FcPattern *pattern; + int height; + int width; + int ascent; + int descent; + int badslant; + int badweight; + short lbearing; + short rbearing; + XftFont *match; + FcFontSet *set; + FcPattern *pattern; } Font; /* Drawing Context */ typedef struct { - Color *col; - size_t collen; - Font font, bfont, ifont, ibfont; - GC gc; + Color *col; + size_t collen; + Font font, bfont, ifont, ibfont; + GC gc; } DC; static inline ushort sixd_to_16bit(int); -static int xmakeglyphfontspecs(XftGlyphFontSpec *, const Glyph *, int, int, - int); +static int xmakeglyphfontspecs(XftGlyphFontSpec *, const Glyph *, int, int, int); static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int); static void xdrawglyph(Glyph, int, int); static void xclear(int, int, int, int); @@ -167,7 +166,7 @@ static void xresize(int, int); static void xhints(void); static int xloadcolor(int, const char *, Color *); static int xloadfont(Font *, FcPattern *); -static void xloadfonts(const char *, double); +static void xloadfonts(char *, double); static int xloadsparefont(FcPattern *, int); static void xloadsparefonts(void); static void xunloadfont(Font *); @@ -203,29 +202,29 @@ static void run(void); static void usage(void); static void (*handler[LASTEvent])(XEvent *) = { - [KeyPress] = kpress, - [ClientMessage] = cmessage, - [ConfigureNotify] = resize, - [VisibilityNotify] = visibility, - [UnmapNotify] = unmap, - [Expose] = expose, - [FocusIn] = focus, - [FocusOut] = focus, - [MotionNotify] = bmotion, - [ButtonPress] = bpress, - [ButtonRelease] = brelease, - /* - * Uncomment if you want the selection to disappear when you select - * something different in another window. - */ - /* [SelectionClear] = selclear_, */ - [SelectionNotify] = selnotify, - /* - * PropertyNotify is only turned on when there is some INCR transfer - * happening for the selection retrieval. - */ - [PropertyNotify] = propnotify, - [SelectionRequest] = selrequest, + [KeyPress] = kpress, + [ClientMessage] = cmessage, + [ConfigureNotify] = resize, + [VisibilityNotify] = visibility, + [UnmapNotify] = unmap, + [Expose] = expose, + [FocusIn] = focus, + [FocusOut] = focus, + [MotionNotify] = bmotion, + [ButtonPress] = bpress, + [ButtonRelease] = brelease, +/* + * Uncomment if you want the selection to disappear when you select something + * different in another window. + */ +/* [SelectionClear] = selclear_, */ + [SelectionNotify] = selnotify, +/* + * PropertyNotify is only turned on when there is some INCR transfer happening + * for the selection retrieval. + */ + [PropertyNotify] = propnotify, + [SelectionRequest] = selrequest, }; /* Globals */ @@ -235,12 +234,17 @@ static XSelection xsel; static TermWindow win; /* Font Ring Cache */ -enum { FRC_NORMAL, FRC_ITALIC, FRC_BOLD, FRC_ITALICBOLD }; +enum { + FRC_NORMAL, + FRC_ITALIC, + FRC_BOLD, + FRC_ITALICBOLD +}; typedef struct { - XftFont *font; - int flags; - Rune unicodep; + XftFont *font; + int flags; + Rune unicodep; } Fontcache; /* Fontcache is an array now. A new font will be appended to the array. */ @@ -253,1620 +257,1742 @@ static double defaultfontsize = 0; static char *opt_alpha = NULL; static char *opt_class = NULL; -static char **opt_cmd = NULL; +static char **opt_cmd = NULL; static char *opt_embed = NULL; -static char *opt_font = NULL; -static char *opt_io = NULL; -static char *opt_line = NULL; -static char *opt_name = NULL; +static char *opt_font = NULL; +static char *opt_io = NULL; +static char *opt_line = NULL; +static char *opt_name = NULL; static char *opt_title = NULL; -static uint buttons; /* bit field of pressed buttons */ +static int oldbutton = 3; /* button event on startup: 3 = release */ int usealtcolors = 0; /* 1 to use alternate palette */ -void clipcopy(const Arg *dummy) { - Atom clipboard; +void +clipcopy(const Arg *dummy) +{ + Atom clipboard; - free(xsel.clipboard); - xsel.clipboard = NULL; + free(xsel.clipboard); + xsel.clipboard = NULL; - if (xsel.primary != NULL) { - xsel.clipboard = xstrdup(xsel.primary); - clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0); - XSetSelectionOwner(xw.dpy, clipboard, xw.win, CurrentTime); - } + if (xsel.primary != NULL) { + xsel.clipboard = xstrdup(xsel.primary); + clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0); + XSetSelectionOwner(xw.dpy, clipboard, xw.win, CurrentTime); + } } -void clippaste(const Arg *dummy) { - Atom clipboard; +void +clippaste(const Arg *dummy) +{ + Atom clipboard; - clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0); - XConvertSelection(xw.dpy, clipboard, xsel.xtarget, clipboard, xw.win, - CurrentTime); + clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0); + XConvertSelection(xw.dpy, clipboard, xsel.xtarget, clipboard, + xw.win, CurrentTime); } -void selpaste(const Arg *dummy) { - XConvertSelection(xw.dpy, XA_PRIMARY, xsel.xtarget, XA_PRIMARY, xw.win, - CurrentTime); +void +selpaste(const Arg *dummy) +{ + XConvertSelection(xw.dpy, XA_PRIMARY, xsel.xtarget, XA_PRIMARY, + xw.win, CurrentTime); } -void numlock(const Arg *dummy) { win.mode ^= MODE_NUMLOCK; } - -void swapcolors(const Arg *dummy) { - usealtcolors = !usealtcolors; - xloadcols(); - redraw(); +void +numlock(const Arg *dummy) +{ + win.mode ^= MODE_NUMLOCK; } -void zoom(const Arg *arg) { - Arg larg; - - larg.f = usedfontsize + arg->f; - zoomabs(&larg); +void +swapcolors(const Arg *dummy) +{ + usealtcolors = !usealtcolors; + xloadcols(); + redraw(); } -void zoomabs(const Arg *arg) { - xunloadfonts(); - xloadfonts(usedfont, arg->f); - xloadsparefonts(); - cresize(0, 0); - redraw(); - xhints(); +void +zoom(const Arg *arg) +{ + Arg larg; + + larg.f = usedfontsize + arg->f; + zoomabs(&larg); } -void zoomreset(const Arg *arg) { - Arg larg; - - if (defaultfontsize > 0) { - larg.f = defaultfontsize; - zoomabs(&larg); - } +void +zoomabs(const Arg *arg) +{ + xunloadfonts(); + xloadfonts(usedfont, arg->f); + xloadsparefonts(); + cresize(0, 0); + redraw(); + xhints(); } -void ttysend(const Arg *arg) { ttywrite(arg->s, strlen(arg->s), 1); } +void +zoomreset(const Arg *arg) +{ + Arg larg; -int evcol(XEvent *e) { - int x = e->xbutton.x - win.hborderpx; - LIMIT(x, 0, win.tw - 1); - return x / win.cw; + if (defaultfontsize > 0) { + larg.f = defaultfontsize; + zoomabs(&larg); + } } -int evrow(XEvent *e) { - int y = e->xbutton.y - win.vborderpx; - LIMIT(y, 0, win.th - 1); - return y / win.ch; +void +ttysend(const Arg *arg) +{ + ttywrite(arg->s, strlen(arg->s), 1); } -void mousesel(XEvent *e, int done) { - int type, seltype = SEL_REGULAR; - uint state = e->xbutton.state & ~(Button1Mask | forcemousemod); - - for (type = 1; type < LEN(selmasks); ++type) { - if (match(selmasks[type], state)) { - seltype = type; - break; - } - } - selextend(evcol(e), evrow(e), seltype, done); - if (done) - setsel(getsel(), e->xbutton.time); +int +evcol(XEvent *e) +{ + int x = e->xbutton.x - win.hborderpx; + LIMIT(x, 0, win.tw - 1); + return x / win.cw; } -void mousereport(XEvent *e) { - int len, btn, code; - int x = evcol(e), y = evrow(e); - int state = e->xbutton.state; - char buf[40]; - static int ox, oy; - - if (e->type == MotionNotify) { - if (x == ox && y == oy) - return; - if (!IS_SET(MODE_MOUSEMOTION) && !IS_SET(MODE_MOUSEMANY)) - return; - /* MODE_MOUSEMOTION: no reporting if no button is pressed */ - if (IS_SET(MODE_MOUSEMOTION) && buttons == 0) - return; - /* Set btn to lowest-numbered pressed button, or 12 if no - * buttons are pressed. */ - for (btn = 1; btn <= 11 && !(buttons & (1 << (btn - 1))); btn++) - ; - code = 32; - } else { - btn = e->xbutton.button; - /* Only buttons 1 through 11 can be encoded */ - if (btn < 1 || btn > 11) - return; - if (e->type == ButtonRelease) { - /* MODE_MOUSEX10: no button release reporting */ - if (IS_SET(MODE_MOUSEX10)) - return; - /* Don't send release events for the scroll wheel */ - if (btn == 4 || btn == 5) - return; - } - code = 0; - } - - ox = x; - oy = y; - - /* Encode btn into code. If no button is pressed for a motion event in - * MODE_MOUSEMANY, then encode it as a release. */ - if ((!IS_SET(MODE_MOUSESGR) && e->type == ButtonRelease) || btn == 12) - code += 3; - else if (btn >= 8) - code += 128 + btn - 8; - else if (btn >= 4) - code += 64 + btn - 4; - else - code += btn - 1; - - if (!IS_SET(MODE_MOUSEX10)) { - code += ((state & ShiftMask) ? 4 : 0) + - ((state & Mod1Mask) ? 8 : 0) /* meta key: alt */ - + ((state & ControlMask) ? 16 : 0); - } - - if (IS_SET(MODE_MOUSESGR)) { - len = snprintf(buf, sizeof(buf), "\033[<%d;%d;%d%c", code, x + 1, y + 1, - e->type == ButtonRelease ? 'm' : 'M'); - } else if (x < 223 && y < 223) { - len = snprintf(buf, sizeof(buf), "\033[M%c%c%c", 32 + code, 32 + x + 1, - 32 + y + 1); - } else { - return; - } - - ttywrite(buf, len, 0); +int +evrow(XEvent *e) +{ + int y = e->xbutton.y - win.vborderpx; + LIMIT(y, 0, win.th - 1); + return y / win.ch; } -uint buttonmask(uint button) { - return button == Button1 ? Button1Mask - : button == Button2 ? Button2Mask - : button == Button3 ? Button3Mask - : button == Button4 ? Button4Mask - : button == Button5 ? Button5Mask - : 0; +void +mousesel(XEvent *e, int done) +{ + int type, seltype = SEL_REGULAR; + uint state = e->xbutton.state & ~(Button1Mask | forcemousemod); + + for (type = 1; type < LEN(selmasks); ++type) { + if (match(selmasks[type], state)) { + seltype = type; + break; + } + } + selextend(evcol(e), evrow(e), seltype, done); + if (done) + setsel(getsel(), e->xbutton.time); } -int mouseaction(XEvent *e, uint release) { - MouseShortcut *ms; +void +mousereport(XEvent *e) +{ + int len, x = evcol(e), y = evrow(e), + button = e->xbutton.button, state = e->xbutton.state; + char buf[40]; + static int ox, oy; - /* ignore Buttonmask for Button - it's set on release */ - uint state = e->xbutton.state & ~buttonmask(e->xbutton.button); + /* from urxvt */ + if (e->xbutton.type == MotionNotify) { + if (x == ox && y == oy) + return; + if (!IS_SET(MODE_MOUSEMOTION) && !IS_SET(MODE_MOUSEMANY)) + return; + /* MOUSE_MOTION: no reporting if no button is pressed */ + if (IS_SET(MODE_MOUSEMOTION) && oldbutton == 3) + return; - for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) { - if (ms->release == release && ms->button == e->xbutton.button && - (!ms->altscrn || (ms->altscrn == (tisaltscr() ? 1 : -1))) && - (match(ms->mod, state) || /* exact or forced */ - match(ms->mod, state & ~forcemousemod))) { - ms->func(&(ms->arg)); - return 1; - } - } + button = oldbutton + 32; + ox = x; + oy = y; + } else { + if (!IS_SET(MODE_MOUSESGR) && e->xbutton.type == ButtonRelease) { + button = 3; + } else { + button -= Button1; + if (button >= 3) + button += 64 - 3; + } + if (e->xbutton.type == ButtonPress) { + oldbutton = button; + ox = x; + oy = y; + } else if (e->xbutton.type == ButtonRelease) { + oldbutton = 3; + /* MODE_MOUSEX10: no button release reporting */ + if (IS_SET(MODE_MOUSEX10)) + return; + if (button == 64 || button == 65) + return; + } + } - return 0; + if (!IS_SET(MODE_MOUSEX10)) { + button += ((state & ShiftMask ) ? 4 : 0) + + ((state & Mod4Mask ) ? 8 : 0) + + ((state & ControlMask) ? 16 : 0); + } + + if (IS_SET(MODE_MOUSESGR)) { + len = snprintf(buf, sizeof(buf), "\033[<%d;%d;%d%c", + button, x+1, y+1, + e->xbutton.type == ButtonRelease ? 'm' : 'M'); + } else if (x < 223 && y < 223) { + len = snprintf(buf, sizeof(buf), "\033[M%c%c%c", + 32+button, 32+x+1, 32+y+1); + } else { + return; + } + + ttywrite(buf, len, 0); } -void bpress(XEvent *e) { - int btn = e->xbutton.button; - struct timespec now; - int snap; - - if (1 <= btn && btn <= 11) - buttons |= 1 << (btn - 1); - - if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) { - mousereport(e); - return; - } - - if (mouseaction(e, 0)) - return; - - if (btn == Button1) { - /* - * If the user clicks below predefined timeouts specific - * snapping behaviour is exposed. - */ - clock_gettime(CLOCK_MONOTONIC, &now); - if (TIMEDIFF(now, xsel.tclick2) <= tripleclicktimeout) { - snap = SNAP_LINE; - } else if (TIMEDIFF(now, xsel.tclick1) <= doubleclicktimeout) { - snap = SNAP_WORD; - } else { - snap = 0; - } - xsel.tclick2 = xsel.tclick1; - xsel.tclick1 = now; - - selstart(evcol(e), evrow(e), snap); - } +uint +buttonmask(uint button) +{ + return button == Button1 ? Button1Mask + : button == Button2 ? Button2Mask + : button == Button3 ? Button3Mask + : button == Button4 ? Button4Mask + : button == Button5 ? Button5Mask + : 0; } -void propnotify(XEvent *e) { - XPropertyEvent *xpev; - Atom clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0); +int +mouseaction(XEvent *e, uint release) +{ + MouseShortcut *ms; - xpev = &e->xproperty; - if (xpev->state == PropertyNewValue && - (xpev->atom == XA_PRIMARY || xpev->atom == clipboard)) { - selnotify(e); - } + /* ignore Buttonmask for Button - it's set on release */ + uint state = e->xbutton.state & ~buttonmask(e->xbutton.button); + + for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) { + if (ms->release == release && + ms->button == e->xbutton.button && + (!ms->altscrn || (ms->altscrn == (tisaltscr() ? 1 : -1))) && + (match(ms->mod, state) || /* exact or forced */ + match(ms->mod, state & ~forcemousemod))) { + ms->func(&(ms->arg)); + return 1; + } + } + + return 0; } -void selnotify(XEvent *e) { - ulong nitems, ofs, rem; - int format; - uchar *data, *last, *repl; - Atom type, incratom, property = None; +void +bpress(XEvent *e) +{ + struct timespec now; + int snap; - incratom = XInternAtom(xw.dpy, "INCR", 0); + if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) { + mousereport(e); + return; + } - ofs = 0; - if (e->type == SelectionNotify) - property = e->xselection.property; - else if (e->type == PropertyNotify) - property = e->xproperty.atom; + if (mouseaction(e, 0)) + return; - if (property == None) - return; + if (e->xbutton.button == Button1) { + /* + * If the user clicks below predefined timeouts specific + * snapping behaviour is exposed. + */ + clock_gettime(CLOCK_MONOTONIC, &now); + if (TIMEDIFF(now, xsel.tclick2) <= tripleclicktimeout) { + snap = SNAP_LINE; + } else if (TIMEDIFF(now, xsel.tclick1) <= doubleclicktimeout) { + snap = SNAP_WORD; + } else { + snap = 0; + } + xsel.tclick2 = xsel.tclick1; + xsel.tclick1 = now; - do { - if (XGetWindowProperty(xw.dpy, xw.win, property, ofs, BUFSIZ / 4, False, - AnyPropertyType, &type, &format, &nitems, &rem, - &data)) { - fprintf(stderr, "Clipboard allocation failed\n"); - return; - } - - if (e->type == PropertyNotify && nitems == 0 && rem == 0) { - /* - * If there is some PropertyNotify with no data, then - * this is the signal of the selection owner that all - * data has been transferred. We won't need to receive - * PropertyNotify events anymore. - */ - MODBIT(xw.attrs.event_mask, 0, PropertyChangeMask); - XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, &xw.attrs); - } - - if (type == incratom) { - /* - * Activate the PropertyNotify events so we receive - * when the selection owner does send us the next - * chunk of data. - */ - MODBIT(xw.attrs.event_mask, 1, PropertyChangeMask); - XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, &xw.attrs); - - /* - * Deleting the property is the transfer start signal. - */ - XDeleteProperty(xw.dpy, xw.win, (int)property); - continue; - } - - /* - * As seen in getsel: - * Line endings are inconsistent in the terminal and GUI world - * copy and pasting. When receiving some selection data, - * replace all '\n' with '\r'. - * FIXME: Fix the computer world. - */ - repl = data; - last = data + nitems * format / 8; - while ((repl = memchr(repl, '\n', last - repl))) { - *repl++ = '\r'; - } - - if (IS_SET(MODE_BRCKTPASTE) && ofs == 0) - ttywrite("\033[200~", 6, 0); - ttywrite((char *)data, nitems * format / 8, 1); - if (IS_SET(MODE_BRCKTPASTE) && rem == 0) - ttywrite("\033[201~", 6, 0); - XFree(data); - /* number of 32-bit chunks returned */ - ofs += nitems * format / 32; - } while (rem > 0); - - /* - * Deleting the property again tells the selection owner to send the - * next data chunk in the property. - */ - XDeleteProperty(xw.dpy, xw.win, (int)property); + selstart(evcol(e), evrow(e), snap); + } } -void xclipcopy(void) { clipcopy(NULL); } +void +propnotify(XEvent *e) +{ + XPropertyEvent *xpev; + Atom clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0); -void selclear_(XEvent *e) { selclear(); } - -void selrequest(XEvent *e) { - XSelectionRequestEvent *xsre; - XSelectionEvent xev; - Atom xa_targets, string, clipboard; - char *seltext; - - xsre = (XSelectionRequestEvent *)e; - xev.type = SelectionNotify; - xev.requestor = xsre->requestor; - xev.selection = xsre->selection; - xev.target = xsre->target; - xev.time = xsre->time; - if (xsre->property == None) - xsre->property = xsre->target; - - /* reject */ - xev.property = None; - - xa_targets = XInternAtom(xw.dpy, "TARGETS", 0); - if (xsre->target == xa_targets) { - /* respond with the supported type */ - string = xsel.xtarget; - XChangeProperty(xsre->display, xsre->requestor, xsre->property, XA_ATOM, 32, - PropModeReplace, (uchar *)&string, 1); - xev.property = xsre->property; - } else if (xsre->target == xsel.xtarget || xsre->target == XA_STRING) { - /* - * xith XA_STRING non ascii characters may be incorrect in the - * requestor. It is not our problem, use utf8. - */ - clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0); - if (xsre->selection == XA_PRIMARY) { - seltext = xsel.primary; - } else if (xsre->selection == clipboard) { - seltext = xsel.clipboard; - } else { - fprintf(stderr, "Unhandled clipboard selection 0x%lx\n", xsre->selection); - return; - } - if (seltext != NULL) { - XChangeProperty(xsre->display, xsre->requestor, xsre->property, - xsre->target, 8, PropModeReplace, (uchar *)seltext, - strlen(seltext)); - xev.property = xsre->property; - } - } - - /* all done, send a notification to the listener */ - if (!XSendEvent(xsre->display, xsre->requestor, 1, 0, (XEvent *)&xev)) - fprintf(stderr, "Error sending SelectionNotify event\n"); + xpev = &e->xproperty; + if (xpev->state == PropertyNewValue && + (xpev->atom == XA_PRIMARY || + xpev->atom == clipboard)) { + selnotify(e); + } } -void setsel(char *str, Time t) { - if (!str) - return; +void +selnotify(XEvent *e) +{ + ulong nitems, ofs, rem; + int format; + uchar *data, *last, *repl; + Atom type, incratom, property = None; - free(xsel.primary); - xsel.primary = str; + incratom = XInternAtom(xw.dpy, "INCR", 0); - XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t); - if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win) - selclear(); - clipcopy(NULL); + ofs = 0; + if (e->type == SelectionNotify) + property = e->xselection.property; + else if (e->type == PropertyNotify) + property = e->xproperty.atom; + + if (property == None) + return; + + do { + if (XGetWindowProperty(xw.dpy, xw.win, property, ofs, + BUFSIZ/4, False, AnyPropertyType, + &type, &format, &nitems, &rem, + &data)) { + fprintf(stderr, "Clipboard allocation failed\n"); + return; + } + + if (e->type == PropertyNotify && nitems == 0 && rem == 0) { + /* + * If there is some PropertyNotify with no data, then + * this is the signal of the selection owner that all + * data has been transferred. We won't need to receive + * PropertyNotify events anymore. + */ + MODBIT(xw.attrs.event_mask, 0, PropertyChangeMask); + XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, + &xw.attrs); + } + + if (type == incratom) { + /* + * Activate the PropertyNotify events so we receive + * when the selection owner does send us the next + * chunk of data. + */ + MODBIT(xw.attrs.event_mask, 1, PropertyChangeMask); + XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, + &xw.attrs); + + /* + * Deleting the property is the transfer start signal. + */ + XDeleteProperty(xw.dpy, xw.win, (int)property); + continue; + } + + /* + * As seen in getsel: + * Line endings are inconsistent in the terminal and GUI world + * copy and pasting. When receiving some selection data, + * replace all '\n' with '\r'. + * FIXME: Fix the computer world. + */ + repl = data; + last = data + nitems * format / 8; + while ((repl = memchr(repl, '\n', last - repl))) { + *repl++ = '\r'; + } + + if (IS_SET(MODE_BRCKTPASTE) && ofs == 0) + ttywrite("\033[200~", 6, 0); + ttywrite((char *)data, nitems * format / 8, 1); + if (IS_SET(MODE_BRCKTPASTE) && rem == 0) + ttywrite("\033[201~", 6, 0); + XFree(data); + /* number of 32-bit chunks returned */ + ofs += nitems * format / 32; + } while (rem > 0); + + /* + * Deleting the property again tells the selection owner to send the + * next data chunk in the property. + */ + XDeleteProperty(xw.dpy, xw.win, (int)property); } -void xsetsel(char *str) { setsel(str, CurrentTime); } - -void brelease(XEvent *e) { - if (!xw.pointerisvisible) { - XDefineCursor(xw.dpy, xw.win, xw.vpointer); - xw.pointerisvisible = 1; - if (!IS_SET(MODE_MOUSEMANY)) - xsetpointermotion(0); - } - int btn = e->xbutton.button; - - if (1 <= btn && btn <= 11) - buttons &= ~(1 << (btn - 1)); - - if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) { - mousereport(e); - return; - } - - if (mouseaction(e, 1)) - return; - if (btn == Button1) - mousesel(e, 1); +void +xclipcopy(void) +{ + clipcopy(NULL); } -void bmotion(XEvent *e) { - if (!xw.pointerisvisible) { - XDefineCursor(xw.dpy, xw.win, xw.vpointer); - xw.pointerisvisible = 1; - if (!IS_SET(MODE_MOUSEMANY)) - xsetpointermotion(0); - } - - if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) { - mousereport(e); - return; - } - - mousesel(e, 0); +void +selclear_(XEvent *e) +{ + selclear(); } -void cresize(int width, int height) { - int col, row; +void +selrequest(XEvent *e) +{ + XSelectionRequestEvent *xsre; + XSelectionEvent xev; + Atom xa_targets, string, clipboard; + char *seltext; - if (width != 0) - win.w = width; - if (height != 0) - win.h = height; + xsre = (XSelectionRequestEvent *) e; + xev.type = SelectionNotify; + xev.requestor = xsre->requestor; + xev.selection = xsre->selection; + xev.target = xsre->target; + xev.time = xsre->time; + if (xsre->property == None) + xsre->property = xsre->target; - col = (win.w - 2 * borderpx) / win.cw; - row = (win.h - 2 * borderpx) / win.ch; - col = MAX(1, col); - row = MAX(1, row); + /* reject */ + xev.property = None; - win.hborderpx = (win.w - col * win.cw) / 2; - win.vborderpx = (win.h - row * win.ch) / 2; + xa_targets = XInternAtom(xw.dpy, "TARGETS", 0); + if (xsre->target == xa_targets) { + /* respond with the supported type */ + string = xsel.xtarget; + XChangeProperty(xsre->display, xsre->requestor, xsre->property, + XA_ATOM, 32, PropModeReplace, + (uchar *) &string, 1); + xev.property = xsre->property; + } else if (xsre->target == xsel.xtarget || xsre->target == XA_STRING) { + /* + * xith XA_STRING non ascii characters may be incorrect in the + * requestor. It is not our problem, use utf8. + */ + clipboard = XInternAtom(xw.dpy, "CLIPBOARD", 0); + if (xsre->selection == XA_PRIMARY) { + seltext = xsel.primary; + } else if (xsre->selection == clipboard) { + seltext = xsel.clipboard; + } else { + fprintf(stderr, + "Unhandled clipboard selection 0x%lx\n", + xsre->selection); + return; + } + if (seltext != NULL) { + XChangeProperty(xsre->display, xsre->requestor, + xsre->property, xsre->target, + 8, PropModeReplace, + (uchar *)seltext, strlen(seltext)); + xev.property = xsre->property; + } + } - tresize(col, row); - xresize(col, row); - ttyresize(win.tw, win.th); + /* all done, send a notification to the listener */ + if (!XSendEvent(xsre->display, xsre->requestor, 1, 0, (XEvent *) &xev)) + fprintf(stderr, "Error sending SelectionNotify event\n"); } -void xresize(int col, int row) { - win.tw = col * win.cw; - win.th = row * win.ch; +void +setsel(char *str, Time t) +{ + if (!str) + return; - XFreePixmap(xw.dpy, xw.buf); - xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, xw.depth); - XftDrawChange(xw.draw, xw.buf); - xclear(0, 0, win.w, win.h); + free(xsel.primary); + xsel.primary = str; - /* resize to new width */ - xw.specbuf = xrealloc(xw.specbuf, col * sizeof(GlyphFontSpec)); + XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t); + if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win) + selclear(); + clipcopy(NULL); } -ushort sixd_to_16bit(int x) { return x == 0 ? 0 : 0x3737 + 0x2828 * x; } - -const char *getcolorname(int i) { - return (usealtcolors) ? altcolorname[i] : colorname[i]; +void +xsetsel(char *str) +{ + setsel(str, CurrentTime); } -int xloadcolor(int i, const char *name, Color *ncolor) { - XRenderColor color = {.alpha = 0xffff}; +void +brelease(XEvent *e) +{ + if (!xw.pointerisvisible) { + XDefineCursor(xw.dpy, xw.win, xw.vpointer); + xw.pointerisvisible = 1; + if (!IS_SET(MODE_MOUSEMANY)) + xsetpointermotion(0); + } - if (!name) { - if (BETWEEN(i, 16, 255)) { /* 256 color */ - if (i < 6 * 6 * 6 + 16) { /* same colors as xterm */ - color.red = sixd_to_16bit(((i - 16) / 36) % 6); - color.green = sixd_to_16bit(((i - 16) / 6) % 6); - color.blue = sixd_to_16bit(((i - 16) / 1) % 6); - } else { /* greyscale */ - color.red = 0x0808 + 0x0a0a * (i - (6 * 6 * 6 + 16)); - color.green = color.blue = color.red; - } - return XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &color, ncolor); - } else - name = getcolorname(i); - } + if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) { + mousereport(e); + return; + } - return XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, ncolor); + if (mouseaction(e, 1)) + return; + if (e->xbutton.button == Button1) + mousesel(e, 1); } -void xloadcols(void) { - int i; - static int loaded; - Color *cp; +void +bmotion(XEvent *e) +{ + if (!xw.pointerisvisible) { + XDefineCursor(xw.dpy, xw.win, xw.vpointer); + xw.pointerisvisible = 1; + if (!IS_SET(MODE_MOUSEMANY)) + xsetpointermotion(0); + } - 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)); - } + if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) { + mousereport(e); + return; + } - for (i = 0; i < dc.collen; i++) - if (!xloadcolor(i, NULL, &dc.col[i])) { - if (getcolorname(i)) - die("could not allocate color '%s'\n", getcolorname(i)); - else - die("could not allocate color %d\n", i); - } - - /* set alpha value of bg color */ - if (opt_alpha) - alpha = strtof(opt_alpha, NULL); - dc.col[defaultbg].color.alpha = (unsigned short)(0xffff * alpha); - dc.col[defaultbg].pixel &= 0x00FFFFFF; - dc.col[defaultbg].pixel |= (unsigned char)(0xff * alpha) << 24; - loaded = 1; + mousesel(e, 0); } -int xgetcolor(int x, unsigned char *r, unsigned char *g, unsigned char *b) { - if (!BETWEEN(x, 0, dc.collen)) - return 1; +void +cresize(int width, int height) +{ + int col, row; - *r = dc.col[x].color.red >> 8; - *g = dc.col[x].color.green >> 8; - *b = dc.col[x].color.blue >> 8; + if (width != 0) + win.w = width; + if (height != 0) + win.h = height; - return 0; + col = (win.w - 2 * borderpx) / win.cw; + row = (win.h - 2 * borderpx) / win.ch; + col = MAX(1, col); + row = MAX(1, row); + + win.hborderpx = (win.w - col * win.cw) / 2; + win.vborderpx = (win.h - row * win.ch) / 2; + + tresize(col, row); + xresize(col, row); + ttyresize(win.tw, win.th); } -int xsetcolorname(int x, const char *name) { - Color ncolor; +void +xresize(int col, int row) +{ + win.tw = col * win.cw; + win.th = row * win.ch; - if (!BETWEEN(x, 0, dc.collen)) - return 1; + XFreePixmap(xw.dpy, xw.buf); + xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, + xw.depth); + XftDrawChange(xw.draw, xw.buf); + xclear(0, 0, win.w, win.h); - if (!xloadcolor(x, name, &ncolor)) - return 1; + /* resize to new width */ + xw.specbuf = xrealloc(xw.specbuf, col * sizeof(GlyphFontSpec)); +} - XftColorFree(xw.dpy, xw.vis, xw.cmap, &dc.col[x]); - dc.col[x] = ncolor; +ushort +sixd_to_16bit(int x) +{ + return x == 0 ? 0 : 0x3737 + 0x2828 * x; +} - return 0; +const char* getcolorname(int i) +{ + return (usealtcolors) ? altcolorname[i] : colorname[i]; +} + +int +xloadcolor(int i, const char *name, Color *ncolor) +{ + XRenderColor color = { .alpha = 0xffff }; + + if (!name) { + if (BETWEEN(i, 16, 255)) { /* 256 color */ + if (i < 6*6*6+16) { /* same colors as xterm */ + color.red = sixd_to_16bit( ((i-16)/36)%6 ); + color.green = sixd_to_16bit( ((i-16)/6) %6 ); + color.blue = sixd_to_16bit( ((i-16)/1) %6 ); + } else { /* greyscale */ + color.red = 0x0808 + 0x0a0a * (i - (6*6*6+16)); + color.green = color.blue = color.red; + } + return XftColorAllocValue(xw.dpy, xw.vis, + xw.cmap, &color, ncolor); + } else + name = getcolorname(i); + } + + return XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, ncolor); +} + +void +xloadcols(void) +{ + int i; + static int loaded; + Color *cp; + + 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 (getcolorname(i)) + die("could not allocate color '%s'\n", getcolorname(i)); + else + die("could not allocate color %d\n", i); + } + + /* set alpha value of bg color */ + if (opt_alpha) + alpha = strtof(opt_alpha, NULL); + dc.col[defaultbg].color.alpha = (unsigned short)(0xffff * alpha); + dc.col[defaultbg].pixel &= 0x00FFFFFF; + dc.col[defaultbg].pixel |= (unsigned char)(0xff * alpha) << 24; + loaded = 1; +} + +int +xsetcolorname(int x, const char *name) +{ + Color ncolor; + + if (!BETWEEN(x, 0, dc.collen)) + return 1; + + if (!xloadcolor(x, name, &ncolor)) + return 1; + + XftColorFree(xw.dpy, xw.vis, xw.cmap, &dc.col[x]); + dc.col[x] = ncolor; + + return 0; } /* * Absolute coordinates. */ -void xclear(int x1, int y1, int x2, int y2) { - XftDrawRect(xw.draw, &dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg], - x1, y1, x2 - x1, y2 - y1); +void +xclear(int x1, int y1, int x2, int y2) +{ + XftDrawRect(xw.draw, + &dc.col[IS_SET(MODE_REVERSE)? defaultfg : defaultbg], + x1, y1, x2-x1, y2-y1); } -void xhints(void) { - XClassHint class = {opt_name ? opt_name : termname, - opt_class ? opt_class : termname}; - XWMHints wm = {.flags = InputHint, .input = 1}; - XSizeHints *sizeh; +void +xhints(void) +{ + XClassHint class = {opt_name ? opt_name : termname, + opt_class ? opt_class : termname}; + XWMHints wm = {.flags = InputHint, .input = 1}; + XSizeHints *sizeh; - sizeh = XAllocSizeHints(); + sizeh = XAllocSizeHints(); - sizeh->flags = PSize | PResizeInc | PBaseSize | PMinSize; - sizeh->height = win.h; - sizeh->width = win.w; - sizeh->height_inc = 1; - sizeh->width_inc = 1; - 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; - sizeh->min_width = sizeh->max_width = win.w; - sizeh->min_height = sizeh->max_height = win.h; - } - if (xw.gm & (XValue | YValue)) { - sizeh->flags |= USPosition | PWinGravity; - sizeh->x = xw.l; - sizeh->y = xw.t; - sizeh->win_gravity = xgeommasktogravity(xw.gm); - } + sizeh->flags = PSize | PResizeInc | PBaseSize | PMinSize; + sizeh->height = win.h; + sizeh->width = win.w; + sizeh->height_inc = 1; + sizeh->width_inc = 1; + 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; + sizeh->min_width = sizeh->max_width = win.w; + sizeh->min_height = sizeh->max_height = win.h; + } + if (xw.gm & (XValue|YValue)) { + sizeh->flags |= USPosition | PWinGravity; + sizeh->x = xw.l; + sizeh->y = xw.t; + sizeh->win_gravity = xgeommasktogravity(xw.gm); + } - XSetWMProperties(xw.dpy, xw.win, NULL, NULL, NULL, 0, sizeh, &wm, &class); - XFree(sizeh); + XSetWMProperties(xw.dpy, xw.win, NULL, NULL, NULL, 0, sizeh, &wm, + &class); + XFree(sizeh); } -int xgeommasktogravity(int mask) { - switch (mask & (XNegative | YNegative)) { - case 0: - return NorthWestGravity; - case XNegative: - return NorthEastGravity; - case YNegative: - return SouthWestGravity; - } +int +xgeommasktogravity(int mask) +{ + switch (mask & (XNegative|YNegative)) { + case 0: + return NorthWestGravity; + case XNegative: + return NorthEastGravity; + case YNegative: + return SouthWestGravity; + } - return SouthEastGravity; + return SouthEastGravity; } -int xloadfont(Font *f, FcPattern *pattern) { - FcPattern *configured; - FcPattern *match; - FcResult result; - XGlyphInfo extents; - int wantattr, haveattr; +int +xloadfont(Font *f, FcPattern *pattern) +{ + FcPattern *configured; + FcPattern *match; + FcResult result; + XGlyphInfo extents; + int wantattr, haveattr; - /* - * Manually configure instead of calling XftMatchFont - * so that we can use the configured pattern for - * "missing glyph" lookups. - */ - configured = FcPatternDuplicate(pattern); - if (!configured) - return 1; + /* + * Manually configure instead of calling XftMatchFont + * so that we can use the configured pattern for + * "missing glyph" lookups. + */ + configured = FcPatternDuplicate(pattern); + if (!configured) + return 1; - FcConfigSubstitute(NULL, configured, FcMatchPattern); - XftDefaultSubstitute(xw.dpy, xw.scr, configured); + FcConfigSubstitute(NULL, configured, FcMatchPattern); + XftDefaultSubstitute(xw.dpy, xw.scr, configured); - match = FcFontMatch(NULL, configured, &result); - if (!match) { - FcPatternDestroy(configured); - return 1; - } + match = FcFontMatch(NULL, configured, &result); + if (!match) { + FcPatternDestroy(configured); + return 1; + } - if (!(f->match = XftFontOpenPattern(xw.dpy, match))) { - FcPatternDestroy(configured); - FcPatternDestroy(match); - return 1; - } + if (!(f->match = XftFontOpenPattern(xw.dpy, match))) { + FcPatternDestroy(configured); + FcPatternDestroy(match); + return 1; + } - if ((XftPatternGetInteger(pattern, "slant", 0, &wantattr) == - XftResultMatch)) { - /* - * Check if xft was unable to find a font with the appropriate - * slant but gave us one anyway. Try to mitigate. - */ - if ((XftPatternGetInteger(f->match->pattern, "slant", 0, &haveattr) != - XftResultMatch) || - haveattr < wantattr) { - f->badslant = 1; - fputs("font slant does not match\n", stderr); - } - } + if ((XftPatternGetInteger(pattern, "slant", 0, &wantattr) == + XftResultMatch)) { + /* + * Check if xft was unable to find a font with the appropriate + * slant but gave us one anyway. Try to mitigate. + */ + if ((XftPatternGetInteger(f->match->pattern, "slant", 0, + &haveattr) != XftResultMatch) || haveattr < wantattr) { + f->badslant = 1; + fputs("font slant does not match\n", stderr); + } + } - if ((XftPatternGetInteger(pattern, "weight", 0, &wantattr) == - XftResultMatch)) { - if ((XftPatternGetInteger(f->match->pattern, "weight", 0, &haveattr) != - XftResultMatch) || - haveattr != wantattr) { - f->badweight = 1; - fputs("font weight does not match\n", stderr); - } - } + if ((XftPatternGetInteger(pattern, "weight", 0, &wantattr) == + XftResultMatch)) { + if ((XftPatternGetInteger(f->match->pattern, "weight", 0, + &haveattr) != XftResultMatch) || haveattr != wantattr) { + f->badweight = 1; + fputs("font weight does not match\n", stderr); + } + } - XftTextExtentsUtf8(xw.dpy, f->match, (const FcChar8 *)ascii_printable, - strlen(ascii_printable), &extents); + XftTextExtentsUtf8(xw.dpy, f->match, + (const FcChar8 *) ascii_printable, + strlen(ascii_printable), &extents); - f->set = NULL; - f->pattern = configured; + f->set = NULL; + f->pattern = configured; - f->ascent = f->match->ascent; - f->descent = f->match->descent; - f->lbearing = 0; - f->rbearing = f->match->max_advance_width; + f->ascent = f->match->ascent; + f->descent = f->match->descent; + f->lbearing = 0; + f->rbearing = f->match->max_advance_width; - f->height = f->ascent + f->descent; - f->width = DIVCEIL(extents.xOff, strlen(ascii_printable)); + f->height = f->ascent + f->descent; + f->width = DIVCEIL(extents.xOff, strlen(ascii_printable)); - return 0; + return 0; } -void xloadfonts(const char *fontstr, double fontsize) { - FcPattern *pattern; - double fontval; +void +xloadfonts(char *fontstr, double fontsize) +{ + FcPattern *pattern; + double fontval; - if (fontstr[0] == '-') - pattern = XftXlfdParse(fontstr, False, False); - else - pattern = FcNameParse((const FcChar8 *)fontstr); + if (fontstr[0] == '-') + pattern = XftXlfdParse(fontstr, False, False); + else + pattern = FcNameParse((FcChar8 *)fontstr); - if (!pattern) - die("can't open font %s\n", fontstr); + if (!pattern) + die("can't open font %s\n", fontstr); - if (fontsize > 1) { - FcPatternDel(pattern, FC_PIXEL_SIZE); - FcPatternDel(pattern, FC_SIZE); - FcPatternAddDouble(pattern, FC_PIXEL_SIZE, (double)fontsize); - usedfontsize = fontsize; - } else { - if (FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &fontval) == - FcResultMatch) { - usedfontsize = fontval; - } else if (FcPatternGetDouble(pattern, FC_SIZE, 0, &fontval) == - FcResultMatch) { - usedfontsize = -1; - } else { - /* - * Default font size is 12, if none given. This is to - * have a known usedfontsize value. - */ - FcPatternAddDouble(pattern, FC_PIXEL_SIZE, 12); - usedfontsize = 12; - } - defaultfontsize = usedfontsize; - } + if (fontsize > 1) { + FcPatternDel(pattern, FC_PIXEL_SIZE); + FcPatternDel(pattern, FC_SIZE); + FcPatternAddDouble(pattern, FC_PIXEL_SIZE, (double)fontsize); + usedfontsize = fontsize; + } else { + if (FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &fontval) == + FcResultMatch) { + usedfontsize = fontval; + } else if (FcPatternGetDouble(pattern, FC_SIZE, 0, &fontval) == + FcResultMatch) { + usedfontsize = -1; + } else { + /* + * Default font size is 12, if none given. This is to + * have a known usedfontsize value. + */ + FcPatternAddDouble(pattern, FC_PIXEL_SIZE, 12); + usedfontsize = 12; + } + defaultfontsize = usedfontsize; + } - if (xloadfont(&dc.font, pattern)) - die("can't open font %s\n", fontstr); + if (xloadfont(&dc.font, pattern)) + die("can't open font %s\n", fontstr); - if (usedfontsize < 0) { - FcPatternGetDouble(dc.font.match->pattern, FC_PIXEL_SIZE, 0, &fontval); - usedfontsize = fontval; - if (fontsize == 0) - defaultfontsize = fontval; - } + if (usedfontsize < 0) { + FcPatternGetDouble(dc.font.match->pattern, + FC_PIXEL_SIZE, 0, &fontval); + usedfontsize = fontval; + if (fontsize == 0) + defaultfontsize = fontval; + } - /* Setting character width and height. */ - win.cw = ceilf(dc.font.width * cwscale); - win.ch = ceilf(dc.font.height * chscale); + /* Setting character width and height. */ + win.cw = ceilf(dc.font.width * cwscale); + win.ch = ceilf(dc.font.height * chscale); - FcPatternDel(pattern, FC_SLANT); - FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); - if (xloadfont(&dc.ifont, pattern)) - die("can't open font %s\n", fontstr); + FcPatternDel(pattern, FC_SLANT); + FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); + if (xloadfont(&dc.ifont, pattern)) + 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("can't open font %s\n", fontstr); + FcPatternDel(pattern, FC_WEIGHT); + FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD); + if (xloadfont(&dc.ibfont, pattern)) + 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("can't open font %s\n", fontstr); + FcPatternDel(pattern, FC_SLANT); + FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN); + if (xloadfont(&dc.bfont, pattern)) + die("can't open font %s\n", fontstr); - FcPatternDestroy(pattern); + FcPatternDestroy(pattern); } -int xloadsparefont(FcPattern *pattern, int flags) { - FcPattern *match; - FcResult result; +int +xloadsparefont(FcPattern *pattern, int flags) +{ + FcPattern *match; + FcResult result; + + match = FcFontMatch(NULL, pattern, &result); + if (!match) { + return 1; + } - match = FcFontMatch(NULL, pattern, &result); - if (!match) { - return 1; - } + if (!(frc[frclen].font = XftFontOpenPattern(xw.dpy, match))) { + FcPatternDestroy(match); + return 1; + } - if (!(frc[frclen].font = XftFontOpenPattern(xw.dpy, match))) { - FcPatternDestroy(match); - return 1; - } + frc[frclen].flags = flags; + /* Believe U+0000 glyph will present in each default font */ + frc[frclen].unicodep = 0; + frclen++; - frc[frclen].flags = flags; - /* Believe U+0000 glyph will present in each default font */ - frc[frclen].unicodep = 0; - frclen++; - - return 0; + return 0; } -void xloadsparefonts(void) { - FcPattern *pattern; - double sizeshift, fontval; - int fc; - char **fp; +void +xloadsparefonts(void) +{ + FcPattern *pattern; + double sizeshift, fontval; + int fc; + char **fp; - if (frclen != 0) - die("can't embed spare fonts. cache isn't empty"); + if (frclen != 0) + die("can't embed spare fonts. cache isn't empty"); - /* Calculate count of spare fonts */ - fc = sizeof(font2) / sizeof(*font2); - if (fc == 0) - return; + /* Calculate count of spare fonts */ + fc = sizeof(font2) / sizeof(*font2); + if (fc == 0) + return; - /* Allocate memory for cache entries. */ - if (frccap < 4 * fc) { - frccap += 4 * fc - frccap; - frc = xrealloc(frc, frccap * sizeof(Fontcache)); - } + /* Allocate memory for cache entries. */ + if (frccap < 4 * fc) { + frccap += 4 * fc - frccap; + frc = xrealloc(frc, frccap * sizeof(Fontcache)); + } - for (fp = font2; fp - font2 < fc; ++fp) { - - if (**fp == '-') - pattern = XftXlfdParse(*fp, False, False); - else - pattern = FcNameParse((FcChar8 *)*fp); - - if (!pattern) - die("can't open spare font %s\n", *fp); - - if (defaultfontsize > 0) { - sizeshift = usedfontsize - defaultfontsize; - if (sizeshift != 0 && FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, - &fontval) == FcResultMatch) { - fontval += sizeshift; - FcPatternDel(pattern, FC_PIXEL_SIZE); - FcPatternDel(pattern, FC_SIZE); - FcPatternAddDouble(pattern, FC_PIXEL_SIZE, fontval); - } - } - - FcPatternAddBool(pattern, FC_SCALABLE, 1); - - FcConfigSubstitute(NULL, pattern, FcMatchPattern); - XftDefaultSubstitute(xw.dpy, xw.scr, pattern); - - if (xloadsparefont(pattern, FRC_NORMAL)) - die("can't open spare font %s\n", *fp); - - FcPatternDel(pattern, FC_SLANT); - FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); - if (xloadsparefont(pattern, FRC_ITALIC)) - die("can't open spare font %s\n", *fp); - - FcPatternDel(pattern, FC_WEIGHT); - FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD); - if (xloadsparefont(pattern, FRC_ITALICBOLD)) - die("can't open spare font %s\n", *fp); - - FcPatternDel(pattern, FC_SLANT); - FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN); - if (xloadsparefont(pattern, FRC_BOLD)) - die("can't open spare font %s\n", *fp); - - FcPatternDestroy(pattern); - } + for (fp = font2; fp - font2 < fc; ++fp) { + + if (**fp == '-') + pattern = XftXlfdParse(*fp, False, False); + else + pattern = FcNameParse((FcChar8 *)*fp); + + if (!pattern) + die("can't open spare font %s\n", *fp); + + if (defaultfontsize > 0) { + sizeshift = usedfontsize - defaultfontsize; + if (sizeshift != 0 && + FcPatternGetDouble(pattern, FC_PIXEL_SIZE, 0, &fontval) == + FcResultMatch) { + fontval += sizeshift; + FcPatternDel(pattern, FC_PIXEL_SIZE); + FcPatternDel(pattern, FC_SIZE); + FcPatternAddDouble(pattern, FC_PIXEL_SIZE, fontval); + } + } + + FcPatternAddBool(pattern, FC_SCALABLE, 1); + + FcConfigSubstitute(NULL, pattern, FcMatchPattern); + XftDefaultSubstitute(xw.dpy, xw.scr, pattern); + + if (xloadsparefont(pattern, FRC_NORMAL)) + die("can't open spare font %s\n", *fp); + + FcPatternDel(pattern, FC_SLANT); + FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); + if (xloadsparefont(pattern, FRC_ITALIC)) + die("can't open spare font %s\n", *fp); + + FcPatternDel(pattern, FC_WEIGHT); + FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD); + if (xloadsparefont(pattern, FRC_ITALICBOLD)) + die("can't open spare font %s\n", *fp); + + FcPatternDel(pattern, FC_SLANT); + FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN); + if (xloadsparefont(pattern, FRC_BOLD)) + die("can't open spare font %s\n", *fp); + + FcPatternDestroy(pattern); + } } -void xunloadfont(Font *f) { - XftFontClose(xw.dpy, f->match); - FcPatternDestroy(f->pattern); - if (f->set) - FcFontSetDestroy(f->set); +void +xunloadfont(Font *f) +{ + XftFontClose(xw.dpy, f->match); + FcPatternDestroy(f->pattern); + if (f->set) + FcFontSetDestroy(f->set); } -void xunloadfonts(void) { - /* Clear Harfbuzz font cache. */ - hbunloadfonts(); +void +xunloadfonts(void) +{ + /* Clear Harfbuzz font cache. */ + hbunloadfonts(); - /* Free the loaded fonts in the font cache. */ - while (frclen > 0) - XftFontClose(xw.dpy, frc[--frclen].font); + /* Free the loaded fonts in the font cache. */ + while (frclen > 0) + XftFontClose(xw.dpy, frc[--frclen].font); - xunloadfont(&dc.font); - xunloadfont(&dc.bfont); - xunloadfont(&dc.ifont); - xunloadfont(&dc.ibfont); + xunloadfont(&dc.font); + xunloadfont(&dc.bfont); + xunloadfont(&dc.ifont); + xunloadfont(&dc.ibfont); } -int ximopen(Display *dpy) { - XIMCallback imdestroy = {.client_data = NULL, .callback = ximdestroy}; - XICCallback icdestroy = {.client_data = NULL, .callback = xicdestroy}; +int +ximopen(Display *dpy) +{ + XIMCallback imdestroy = { .client_data = NULL, .callback = ximdestroy }; + XICCallback icdestroy = { .client_data = NULL, .callback = xicdestroy }; - xw.ime.xim = XOpenIM(xw.dpy, NULL, NULL, NULL); - if (xw.ime.xim == NULL) - return 0; + xw.ime.xim = XOpenIM(xw.dpy, NULL, NULL, NULL); + if (xw.ime.xim == NULL) + return 0; - if (XSetIMValues(xw.ime.xim, XNDestroyCallback, &imdestroy, NULL)) - fprintf(stderr, "XSetIMValues: " - "Could not set XNDestroyCallback.\n"); + if (XSetIMValues(xw.ime.xim, XNDestroyCallback, &imdestroy, NULL)) + fprintf(stderr, "XSetIMValues: " + "Could not set XNDestroyCallback.\n"); - xw.ime.spotlist = XVaCreateNestedList(0, XNSpotLocation, &xw.ime.spot, NULL); + xw.ime.spotlist = XVaCreateNestedList(0, XNSpotLocation, &xw.ime.spot, + NULL); - if (xw.ime.xic == NULL) { - xw.ime.xic = XCreateIC(xw.ime.xim, XNInputStyle, - XIMPreeditNothing | XIMStatusNothing, XNClientWindow, - xw.win, XNDestroyCallback, &icdestroy, NULL); - } - if (xw.ime.xic == NULL) - fprintf(stderr, "XCreateIC: Could not create input context.\n"); + if (xw.ime.xic == NULL) { + xw.ime.xic = XCreateIC(xw.ime.xim, XNInputStyle, + XIMPreeditNothing | XIMStatusNothing, + XNClientWindow, xw.win, + XNDestroyCallback, &icdestroy, + NULL); + } + if (xw.ime.xic == NULL) + fprintf(stderr, "XCreateIC: Could not create input context.\n"); - return 1; + return 1; } -void ximinstantiate(Display *dpy, XPointer client, XPointer call) { - if (ximopen(dpy)) - XUnregisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL, ximinstantiate, - NULL); +void +ximinstantiate(Display *dpy, XPointer client, XPointer call) +{ + if (ximopen(dpy)) + XUnregisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL, + ximinstantiate, NULL); } -void ximdestroy(XIM xim, XPointer client, XPointer call) { - xw.ime.xim = NULL; - XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL, ximinstantiate, - NULL); - XFree(xw.ime.spotlist); +void +ximdestroy(XIM xim, XPointer client, XPointer call) +{ + xw.ime.xim = NULL; + XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL, + ximinstantiate, NULL); + XFree(xw.ime.spotlist); } -int xicdestroy(XIC xim, XPointer client, XPointer call) { - xw.ime.xic = NULL; - return 1; +int +xicdestroy(XIC xim, XPointer client, XPointer call) +{ + xw.ime.xic = NULL; + return 1; } -void xinit(int cols, int rows) { - XGCValues gcvalues; - Window parent; - pid_t thispid = getpid(); - XColor xmousefg, xmousebg; - Pixmap blankpm; - XWindowAttributes attr; - XVisualInfo vis; +void +xinit(int cols, int rows) +{ + XGCValues gcvalues; + Window parent; + pid_t thispid = getpid(); + XColor xmousefg, xmousebg; + Pixmap blankpm; + XWindowAttributes attr; + XVisualInfo vis; - if (!(xw.dpy = XOpenDisplay(NULL))) - die("can't open display\n"); - xw.scr = XDefaultScreen(xw.dpy); + if (!(xw.dpy = XOpenDisplay(NULL))) + die("can't open display\n"); + xw.scr = XDefaultScreen(xw.dpy); - if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0)))) { - parent = XRootWindow(xw.dpy, xw.scr); - xw.depth = 32; - } else { - XGetWindowAttributes(xw.dpy, parent, &attr); - xw.depth = attr.depth; - } + if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0)))) { + parent = XRootWindow(xw.dpy, xw.scr); + xw.depth = 32; + } else { + XGetWindowAttributes(xw.dpy, parent, &attr); + xw.depth = attr.depth; + } - XMatchVisualInfo(xw.dpy, xw.scr, xw.depth, TrueColor, &vis); - xw.vis = vis.visual; + XMatchVisualInfo(xw.dpy, xw.scr, xw.depth, TrueColor, &vis); + xw.vis = vis.visual; - /* font */ - if (!FcInit()) - die("could not init fontconfig.\n"); + /* font */ + if (!FcInit()) + die("could not init fontconfig.\n"); - usedfont = (opt_font == NULL) ? font : opt_font; - xloadfonts(usedfont, 0); + usedfont = (opt_font == NULL)? font : opt_font; + xloadfonts(usedfont, 0); - /* spare fonts */ - xloadsparefonts(); + /* spare fonts */ + xloadsparefonts(); - /* colors */ - xw.cmap = XCreateColormap(xw.dpy, parent, xw.vis, None); - xloadcols(); + /* colors */ + xw.cmap = XCreateColormap(xw.dpy, parent, xw.vis, None); + xloadcols(); - /* adjust fixed window geometry */ - win.w = 2 * win.hborderpx + cols * win.cw; - win.h = 2 * win.vborderpx + rows * win.ch; - if (xw.gm & XNegative) - xw.l += DisplayWidth(xw.dpy, xw.scr) - win.w - 2; - if (xw.gm & YNegative) - xw.t += DisplayHeight(xw.dpy, xw.scr) - win.h - 2; + /* adjust fixed window geometry */ + win.w = 2 * win.hborderpx + cols * win.cw; + win.h = 2 * win.vborderpx + rows * win.ch; + if (xw.gm & XNegative) + xw.l += DisplayWidth(xw.dpy, xw.scr) - win.w - 2; + if (xw.gm & YNegative) + xw.t += DisplayHeight(xw.dpy, xw.scr) - win.h - 2; - /* Events */ - 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 | KeyReleaseMask | - ExposureMask | VisibilityChangeMask | - StructureNotifyMask | ButtonMotionMask | - ButtonPressMask | ButtonReleaseMask; - xw.attrs.colormap = xw.cmap; + /* Events */ + 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 | KeyReleaseMask + | ExposureMask | VisibilityChangeMask | StructureNotifyMask + | ButtonMotionMask | ButtonPressMask | ButtonReleaseMask; + xw.attrs.colormap = xw.cmap; - xw.win = XCreateWindow(xw.dpy, parent, xw.l, xw.t, win.w, win.h, 0, xw.depth, - InputOutput, xw.vis, - CWBackPixel | CWBorderPixel | CWBitGravity | - CWEventMask | CWColormap, - &xw.attrs); + xw.win = XCreateWindow(xw.dpy, parent, xw.l, xw.t, + win.w, win.h, 0, xw.depth, InputOutput, + xw.vis, CWBackPixel | CWBorderPixel | CWBitGravity + | CWEventMask | CWColormap, &xw.attrs); - memset(&gcvalues, 0, sizeof(gcvalues)); - gcvalues.graphics_exposures = False; - xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, xw.depth); - dc.gc = XCreateGC(xw.dpy, xw.buf, GCGraphicsExposures, &gcvalues); - XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel); - XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h); + memset(&gcvalues, 0, sizeof(gcvalues)); + gcvalues.graphics_exposures = False; + xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, xw.depth); + dc.gc = XCreateGC(xw.dpy, xw.buf, GCGraphicsExposures, &gcvalues); + XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel); + XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h); - /* font spec buffer */ - xw.specbuf = xmalloc(cols * sizeof(GlyphFontSpec)); + /* font spec buffer */ + xw.specbuf = xmalloc(cols * sizeof(GlyphFontSpec)); - /* Xft rendering context */ - xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap); + /* Xft rendering context */ + xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap); - /* input methods */ - if (!ximopen(xw.dpy)) { - XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL, ximinstantiate, - NULL); - } + /* input methods */ + if (!ximopen(xw.dpy)) { + XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL, + ximinstantiate, NULL); + } - /* white cursor, black outline */ - xw.pointerisvisible = 1; - xw.vpointer = XCreateFontCursor(xw.dpy, mouseshape); - XDefineCursor(xw.dpy, xw.win, xw.vpointer); + /* white cursor, black outline */ + xw.pointerisvisible = 1; + xw.vpointer = XCreateFontCursor(xw.dpy, mouseshape); + XDefineCursor(xw.dpy, xw.win, xw.vpointer); - if (XParseColor(xw.dpy, xw.cmap, getcolorname(mousefg), &xmousefg) == 0) { - xmousefg.red = 0xffff; - xmousefg.green = 0xffff; - xmousefg.blue = 0xffff; - } + if (XParseColor(xw.dpy, xw.cmap, getcolorname(mousefg), &xmousefg) == 0) { + xmousefg.red = 0xffff; + xmousefg.green = 0xffff; + xmousefg.blue = 0xffff; + } - if (XParseColor(xw.dpy, xw.cmap, getcolorname(mousebg), &xmousebg) == 0) { - xmousebg.red = 0x0000; - xmousebg.green = 0x0000; - xmousebg.blue = 0x0000; - } + if (XParseColor(xw.dpy, xw.cmap, getcolorname(mousebg), &xmousebg) == 0) { + xmousebg.red = 0x0000; + xmousebg.green = 0x0000; + xmousebg.blue = 0x0000; + } - XRecolorCursor(xw.dpy, xw.vpointer, &xmousefg, &xmousebg); - blankpm = XCreateBitmapFromData(xw.dpy, xw.win, &(char){0}, 1, 1); - xw.bpointer = - XCreatePixmapCursor(xw.dpy, blankpm, blankpm, &xmousefg, &xmousebg, 0, 0); + XRecolorCursor(xw.dpy, xw.vpointer, &xmousefg, &xmousebg); + blankpm = XCreateBitmapFromData(xw.dpy, xw.win, &(char){0}, 1, 1); + xw.bpointer = XCreatePixmapCursor(xw.dpy, blankpm, blankpm, + &xmousefg, &xmousebg, 0, 0); - xw.xembed = XInternAtom(xw.dpy, "_XEMBED", False); - xw.wmdeletewin = XInternAtom(xw.dpy, "WM_DELETE_WINDOW", False); - xw.netwmname = XInternAtom(xw.dpy, "_NET_WM_NAME", False); - xw.netwmiconname = XInternAtom(xw.dpy, "_NET_WM_ICON_NAME", False); - XSetWMProtocols(xw.dpy, xw.win, &xw.wmdeletewin, 1); + xw.xembed = XInternAtom(xw.dpy, "_XEMBED", False); + xw.wmdeletewin = XInternAtom(xw.dpy, "WM_DELETE_WINDOW", False); + xw.netwmname = XInternAtom(xw.dpy, "_NET_WM_NAME", False); + XSetWMProtocols(xw.dpy, xw.win, &xw.wmdeletewin, 1); - xw.netwmpid = XInternAtom(xw.dpy, "_NET_WM_PID", False); - XChangeProperty(xw.dpy, xw.win, xw.netwmpid, XA_CARDINAL, 32, PropModeReplace, - (uchar *)&thispid, 1); + xw.netwmpid = XInternAtom(xw.dpy, "_NET_WM_PID", False); + XChangeProperty(xw.dpy, xw.win, xw.netwmpid, XA_CARDINAL, 32, + PropModeReplace, (uchar *)&thispid, 1); - win.mode = MODE_NUMLOCK; - resettitle(); - xhints(); - XMapWindow(xw.dpy, xw.win); - XSync(xw.dpy, False); + win.mode = MODE_NUMLOCK; + resettitle(); + xhints(); + XMapWindow(xw.dpy, xw.win); + XSync(xw.dpy, False); - clock_gettime(CLOCK_MONOTONIC, &xsel.tclick1); - clock_gettime(CLOCK_MONOTONIC, &xsel.tclick2); - xsel.primary = NULL; - xsel.clipboard = NULL; - xsel.xtarget = XInternAtom(xw.dpy, "UTF8_STRING", 0); - if (xsel.xtarget == None) - xsel.xtarget = XA_STRING; + clock_gettime(CLOCK_MONOTONIC, &xsel.tclick1); + clock_gettime(CLOCK_MONOTONIC, &xsel.tclick2); + xsel.primary = NULL; + xsel.clipboard = NULL; + xsel.xtarget = XInternAtom(xw.dpy, "UTF8_STRING", 0); + if (xsel.xtarget == None) + xsel.xtarget = XA_STRING; - boxdraw_xinit(xw.dpy, xw.cmap, xw.draw, xw.vis); + boxdraw_xinit(xw.dpy, xw.cmap, xw.draw, xw.vis); } -int xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, - int x, int y) { - float winx = win.hborderpx + x * win.cw, winy = win.vborderpx + y * win.ch, - xp, yp; - ushort mode, prevmode = USHRT_MAX; - Font *font = &dc.font; - int frcflags = FRC_NORMAL; - float runewidth = win.cw; - Rune rune; - FT_UInt glyphidx; - FcResult fcres; - FcPattern *fcpattern, *fontpattern; - FcFontSet *fcsets[] = {NULL}; - FcCharSet *fccharset; - int i, f, numspecs = 0; +int +xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x, int y) +{ + float winx = win.hborderpx + x * win.cw, winy = win.vborderpx + y * win.ch, xp, yp; + ushort mode, prevmode = USHRT_MAX; + Font *font = &dc.font; + int frcflags = FRC_NORMAL; + float runewidth = win.cw; + Rune rune; + FT_UInt glyphidx; + FcResult fcres; + FcPattern *fcpattern, *fontpattern; + FcFontSet *fcsets[] = { NULL }; + FcCharSet *fccharset; + int i, f, numspecs = 0; - for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) { - /* Fetch rune and mode for current glyph. */ - rune = glyphs[i].u; - mode = glyphs[i].mode; + for (i = 0, xp = winx, yp = winy + font->ascent; i < len; ++i) { + /* Fetch rune and mode for current glyph. */ + rune = glyphs[i].u; + mode = glyphs[i].mode; - /* Skip dummy wide-character spacing. */ - if (mode & ATTR_WDUMMY) - continue; + /* Skip dummy wide-character spacing. */ + if (mode & ATTR_WDUMMY) + continue; - /* Determine font for glyph if different from previous glyph. */ - if (prevmode != mode) { - prevmode = mode; - font = &dc.font; - frcflags = FRC_NORMAL; - runewidth = win.cw * ((mode & ATTR_WIDE) ? 2.0f : 1.0f); - if ((mode & ATTR_ITALIC) && (mode & ATTR_BOLD)) { - font = &dc.ibfont; - frcflags = FRC_ITALICBOLD; - } else if (mode & ATTR_ITALIC) { - font = &dc.ifont; - frcflags = FRC_ITALIC; - } else if (mode & ATTR_BOLD) { - font = &dc.bfont; - frcflags = FRC_BOLD; - } - yp = winy + font->ascent; - } + /* Determine font for glyph if different from previous glyph. */ + if (prevmode != mode) { + prevmode = mode; + font = &dc.font; + frcflags = FRC_NORMAL; + runewidth = win.cw * ((mode & ATTR_WIDE) ? 2.0f : 1.0f); + if ((mode & ATTR_ITALIC) && (mode & ATTR_BOLD)) { + font = &dc.ibfont; + frcflags = FRC_ITALICBOLD; + } else if (mode & ATTR_ITALIC) { + font = &dc.ifont; + frcflags = FRC_ITALIC; + } else if (mode & ATTR_BOLD) { + font = &dc.bfont; + frcflags = FRC_BOLD; + } + yp = winy + font->ascent; + } - if (mode & ATTR_BOXDRAW) { - /* minor shoehorning: boxdraw uses only this ushort */ - glyphidx = boxdrawindex(&glyphs[i]); - } else { - /* Lookup character index with default font. */ - glyphidx = XftCharIndex(xw.dpy, font->match, rune); - } - if (glyphidx) { - specs[numspecs].font = font->match; - specs[numspecs].glyph = glyphidx; - specs[numspecs].x = (short)xp; - specs[numspecs].y = (short)yp; - xp += runewidth; - numspecs++; - continue; - } + if (mode & ATTR_BOXDRAW) { + /* minor shoehorning: boxdraw uses only this ushort */ + glyphidx = boxdrawindex(&glyphs[i]); + } else { + /* Lookup character index with default font. */ + glyphidx = XftCharIndex(xw.dpy, font->match, rune); + } + if (glyphidx) { + specs[numspecs].font = font->match; + specs[numspecs].glyph = glyphidx; + specs[numspecs].x = (short)xp; + specs[numspecs].y = (short)yp; + xp += runewidth; + numspecs++; + continue; + } - /* Fallback on font cache, search the font cache for match. */ - for (f = 0; f < frclen; f++) { - glyphidx = XftCharIndex(xw.dpy, frc[f].font, rune); - /* Everything correct. */ - if (glyphidx && frc[f].flags == frcflags) - break; - /* We got a default font for a not found glyph. */ - if (!glyphidx && frc[f].flags == frcflags && frc[f].unicodep == rune) { - break; - } - } + /* Fallback on font cache, search the font cache for match. */ + for (f = 0; f < frclen; f++) { + glyphidx = XftCharIndex(xw.dpy, frc[f].font, rune); + /* Everything correct. */ + if (glyphidx && frc[f].flags == frcflags) + break; + /* We got a default font for a not found glyph. */ + if (!glyphidx && frc[f].flags == frcflags + && frc[f].unicodep == rune) { + break; + } + } - /* Nothing was found. Use fontconfig to find matching font. */ - if (f >= frclen) { - if (!font->set) - font->set = FcFontSort(0, font->pattern, 1, 0, &fcres); - fcsets[0] = font->set; + /* Nothing was found. Use fontconfig to find matching font. */ + if (f >= frclen) { + if (!font->set) + font->set = FcFontSort(0, font->pattern, + 1, 0, &fcres); + fcsets[0] = font->set; - /* - * Nothing was found in the cache. Now use - * some dozen of Fontconfig calls to get the - * font for one single character. - * - * Xft and fontconfig are design failures. - */ - fcpattern = FcPatternDuplicate(font->pattern); - fccharset = FcCharSetCreate(); + /* + * Nothing was found in the cache. Now use + * some dozen of Fontconfig calls to get the + * font for one single character. + * + * Xft and fontconfig are design failures. + */ + fcpattern = FcPatternDuplicate(font->pattern); + fccharset = FcCharSetCreate(); - FcCharSetAddChar(fccharset, rune); - FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset); - FcPatternAddBool(fcpattern, FC_SCALABLE, 1); + FcCharSetAddChar(fccharset, rune); + FcPatternAddCharSet(fcpattern, FC_CHARSET, + fccharset); + FcPatternAddBool(fcpattern, FC_SCALABLE, 1); - FcConfigSubstitute(0, fcpattern, FcMatchPattern); - FcDefaultSubstitute(fcpattern); + FcConfigSubstitute(0, fcpattern, + FcMatchPattern); + FcDefaultSubstitute(fcpattern); - fontpattern = FcFontSetMatch(0, fcsets, 1, fcpattern, &fcres); + fontpattern = FcFontSetMatch(0, fcsets, 1, + fcpattern, &fcres); - /* Allocate memory for the new cache entry. */ - if (frclen >= frccap) { - frccap += 16; - frc = xrealloc(frc, frccap * sizeof(Fontcache)); - } + /* Allocate memory for the new cache entry. */ + if (frclen >= frccap) { + frccap += 16; + frc = xrealloc(frc, frccap * sizeof(Fontcache)); + } - frc[frclen].font = XftFontOpenPattern(xw.dpy, fontpattern); - if (!frc[frclen].font) - die("XftFontOpenPattern failed seeking fallback font: %s\n", - strerror(errno)); - frc[frclen].flags = frcflags; - frc[frclen].unicodep = rune; + frc[frclen].font = XftFontOpenPattern(xw.dpy, + fontpattern); + if (!frc[frclen].font) + die("XftFontOpenPattern failed seeking fallback font: %s\n", + strerror(errno)); + frc[frclen].flags = frcflags; + frc[frclen].unicodep = rune; - glyphidx = XftCharIndex(xw.dpy, frc[frclen].font, rune); + glyphidx = XftCharIndex(xw.dpy, frc[frclen].font, rune); - f = frclen; - frclen++; + f = frclen; + frclen++; - FcPatternDestroy(fcpattern); - FcCharSetDestroy(fccharset); - } + FcPatternDestroy(fcpattern); + FcCharSetDestroy(fccharset); + } - specs[numspecs].font = frc[f].font; - specs[numspecs].glyph = glyphidx; - specs[numspecs].x = (short)xp; - specs[numspecs].y = (short)yp; - xp += runewidth; - numspecs++; - } + specs[numspecs].font = frc[f].font; + specs[numspecs].glyph = glyphidx; + specs[numspecs].x = (short)xp; + specs[numspecs].y = (short)yp; + xp += runewidth; + numspecs++; + } - /* Harfbuzz transformation for ligatures. */ - hbtransform(specs, glyphs, len, x, y); + /* Harfbuzz transformation for ligatures. */ + hbtransform(specs, glyphs, len, x, y); - return numspecs; + return numspecs; } -void xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, - int x, int y) { - int charlen = len * ((base.mode & ATTR_WIDE) ? 2 : 1); - int winx = win.hborderpx + x * win.cw, winy = win.vborderpx + y * win.ch, - width = charlen * win.cw; - Color *fg, *bg, *temp, revfg, revbg, truefg, truebg; - XRenderColor colfg, colbg; - XRectangle r; +void +xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, int y) +{ + int charlen = len * ((base.mode & ATTR_WIDE) ? 2 : 1); + int winx = win.hborderpx + x * win.cw, winy = win.vborderpx + y * win.ch, + width = charlen * win.cw; + Color *fg, *bg, *temp, revfg, revbg, truefg, truebg; + XRenderColor colfg, colbg; + XRectangle r; - /* Fallback on color display for attributes not supported by the font */ - if (base.mode & ATTR_ITALIC && base.mode & ATTR_BOLD) { - if (dc.ibfont.badslant || dc.ibfont.badweight) - base.fg = defaultattr; - } else if ((base.mode & ATTR_ITALIC && dc.ifont.badslant) || - (base.mode & ATTR_BOLD && dc.bfont.badweight)) { - base.fg = defaultattr; - } + /* Fallback on color display for attributes not supported by the font */ + if (base.mode & ATTR_ITALIC && base.mode & ATTR_BOLD) { + if (dc.ibfont.badslant || dc.ibfont.badweight) + base.fg = defaultattr; + } else if ((base.mode & ATTR_ITALIC && dc.ifont.badslant) || + (base.mode & ATTR_BOLD && dc.bfont.badweight)) { + base.fg = defaultattr; + } - if (IS_TRUECOL(base.fg)) { - colfg.alpha = 0xffff; - colfg.red = TRUERED(base.fg); - colfg.green = TRUEGREEN(base.fg); - colfg.blue = TRUEBLUE(base.fg); - XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colfg, &truefg); - fg = &truefg; - } else { - fg = &dc.col[base.fg]; - } + if (IS_TRUECOL(base.fg)) { + colfg.alpha = 0xffff; + colfg.red = TRUERED(base.fg); + colfg.green = TRUEGREEN(base.fg); + colfg.blue = TRUEBLUE(base.fg); + XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colfg, &truefg); + fg = &truefg; + } else { + fg = &dc.col[base.fg]; + } - if (IS_TRUECOL(base.bg)) { - colbg.alpha = 0xffff; - colbg.green = TRUEGREEN(base.bg); - colbg.red = TRUERED(base.bg); - colbg.blue = TRUEBLUE(base.bg); - XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colbg, &truebg); - bg = &truebg; - } else { - bg = &dc.col[base.bg]; - } + if (IS_TRUECOL(base.bg)) { + colbg.alpha = 0xffff; + colbg.green = TRUEGREEN(base.bg); + colbg.red = TRUERED(base.bg); + colbg.blue = TRUEBLUE(base.bg); + XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colbg, &truebg); + bg = &truebg; + } else { + bg = &dc.col[base.bg]; + } - /* Change basic system colors [0-7] to bright system colors [8-15] */ - if ((base.mode & ATTR_BOLD_FAINT) == ATTR_BOLD && BETWEEN(base.fg, 0, 7)) - fg = &dc.col[base.fg]; + /* Change basic system colors [0-7] to bright system colors [8-15] */ + if ((base.mode & ATTR_BOLD_FAINT) == ATTR_BOLD && BETWEEN(base.fg, 0, 7)) + fg = &dc.col[base.fg]; - if (IS_SET(MODE_REVERSE)) { - if (fg == &dc.col[defaultfg]) { - fg = &dc.col[defaultbg]; - } else { - colfg.red = ~fg->color.red; - colfg.green = ~fg->color.green; - colfg.blue = ~fg->color.blue; - colfg.alpha = fg->color.alpha; - XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colfg, &revfg); - fg = &revfg; - } + if (IS_SET(MODE_REVERSE)) { + if (fg == &dc.col[defaultfg]) { + fg = &dc.col[defaultbg]; + } else { + colfg.red = ~fg->color.red; + colfg.green = ~fg->color.green; + colfg.blue = ~fg->color.blue; + colfg.alpha = fg->color.alpha; + XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colfg, + &revfg); + fg = &revfg; + } - if (bg == &dc.col[defaultbg]) { - bg = &dc.col[defaultfg]; - } else { - colbg.red = ~bg->color.red; - colbg.green = ~bg->color.green; - colbg.blue = ~bg->color.blue; - colbg.alpha = bg->color.alpha; - XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colbg, &revbg); - bg = &revbg; - } - } + if (bg == &dc.col[defaultbg]) { + bg = &dc.col[defaultfg]; + } else { + colbg.red = ~bg->color.red; + colbg.green = ~bg->color.green; + colbg.blue = ~bg->color.blue; + colbg.alpha = bg->color.alpha; + XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colbg, + &revbg); + bg = &revbg; + } + } - if ((base.mode & ATTR_BOLD_FAINT) == ATTR_FAINT) { - colfg.red = fg->color.red / 2; - colfg.green = fg->color.green / 2; - colfg.blue = fg->color.blue / 2; - colfg.alpha = fg->color.alpha; - XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colfg, &revfg); - fg = &revfg; - } + if ((base.mode & ATTR_BOLD_FAINT) == ATTR_FAINT) { + colfg.red = fg->color.red / 2; + colfg.green = fg->color.green / 2; + colfg.blue = fg->color.blue / 2; + colfg.alpha = fg->color.alpha; + XftColorAllocValue(xw.dpy, xw.vis, xw.cmap, &colfg, &revfg); + fg = &revfg; + } - if (base.mode & ATTR_REVERSE) { - temp = fg; - fg = bg; - bg = temp; - } + if (base.mode & ATTR_REVERSE) { + temp = fg; + fg = bg; + bg = temp; + } - if (base.mode & ATTR_BLINK && win.mode & MODE_BLINK) - fg = bg; + if (base.mode & ATTR_BLINK && win.mode & MODE_BLINK) + fg = bg; - if (base.mode & ATTR_INVISIBLE) - fg = bg; + if (base.mode & ATTR_INVISIBLE) + fg = bg; - /* Intelligent cleaning up of the borders. */ - if (x == 0) { - xclear(0, (y == 0) ? 0 : winy, win.vborderpx, - winy + win.ch + - ((winy + win.ch >= win.vborderpx + win.th) ? win.h : 0)); - } - if (winx + width >= win.hborderpx + win.tw) { - xclear( - winx + width, (y == 0) ? 0 : winy, win.w, - ((winy + win.ch >= win.vborderpx + win.th) ? win.h : (winy + win.ch))); - } - if (y == 0) - xclear(winx, 0, winx + width, win.hborderpx); - if (winy + win.ch >= win.vborderpx + win.th) - xclear(winx, winy + win.ch, winx + width, win.h); + /* Intelligent cleaning up of the borders. */ + if (x == 0) { + xclear(0, (y == 0)? 0 : winy, win.vborderpx, + winy + win.ch + + ((winy + win.ch >= win.vborderpx + win.th)? win.h : 0)); + } + if (winx + width >= win.hborderpx + win.tw) { + xclear(winx + width, (y == 0)? 0 : winy, win.w, + ((winy + win.ch >= win.vborderpx + win.th)? win.h : (winy + win.ch))); + } + if (y == 0) + xclear(winx, 0, winx + width, win.hborderpx); + if (winy + win.ch >= win.vborderpx + win.th) + xclear(winx, winy + win.ch, winx + width, win.h); - /* Clean up the region we want to draw to. */ - XftDrawRect(xw.draw, bg, winx, winy, width, win.ch); + /* Clean up the region we want to draw to. */ + XftDrawRect(xw.draw, bg, winx, winy, width, win.ch); - /* Set the clip region because Xft is sometimes dirty. */ - r.x = 0; - r.y = 0; - r.height = win.ch; - r.width = width; - XftDrawSetClipRectangles(xw.draw, winx, winy, &r, 1); + /* Set the clip region because Xft is sometimes dirty. */ + r.x = 0; + r.y = 0; + r.height = win.ch; + r.width = width; + XftDrawSetClipRectangles(xw.draw, winx, winy, &r, 1); - if (base.mode & ATTR_BOXDRAW) { - drawboxes(winx, winy, width / len, win.ch, fg, bg, specs, len); - } else { - /* Render the glyphs. */ - XftDrawGlyphFontSpec(xw.draw, fg, specs, len); - } + if (base.mode & ATTR_BOXDRAW) { + drawboxes(winx, winy, width / len, win.ch, fg, bg, specs, len); + } else { + /* Render the glyphs. */ + XftDrawGlyphFontSpec(xw.draw, fg, specs, len); + } - /* Render underline and strikethrough. */ - if (base.mode & ATTR_UNDERLINE) { - XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent + 1, width, 1); - } + /* Render underline and strikethrough. */ + if (base.mode & ATTR_UNDERLINE) { + XftDrawRect(xw.draw, fg, winx, winy + dc.font.ascent + 1, + width, 1); + } - if (base.mode & ATTR_STRUCK) { - XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent / 3, width, 1); - } + if (base.mode & ATTR_STRUCK) { + XftDrawRect(xw.draw, fg, winx, winy + 2 * dc.font.ascent / 3, + width, 1); + } - /* Reset clip to none. */ - XftDrawSetClip(xw.draw, 0); + /* Reset clip to none. */ + XftDrawSetClip(xw.draw, 0); } -void xdrawglyph(Glyph g, int x, int y) { - int numspecs; - XftGlyphFontSpec spec; +void +xdrawglyph(Glyph g, int x, int y) +{ + int numspecs; + XftGlyphFontSpec spec; - numspecs = xmakeglyphfontspecs(&spec, &g, 1, x, y); - xdrawglyphfontspecs(&spec, g, numspecs, x, y); + numspecs = xmakeglyphfontspecs(&spec, &g, 1, x, y); + xdrawglyphfontspecs(&spec, g, numspecs, x, y); } -void xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og, Line line, - int len) { - Color drawcol; +void +xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og, Line line, int len) +{ + Color drawcol; - /* remove the old cursor */ - if (selected(ox, oy)) - og.mode ^= ATTR_REVERSE; + /* remove the old cursor */ + if (selected(ox, oy)) + og.mode ^= ATTR_REVERSE; - /* Redraw the line where cursor was previously. - * It will restore the ligatures broken by the cursor. */ - xdrawline(line, 0, oy, len); + /* Redraw the line where cursor was previously. + * It will restore the ligatures broken by the cursor. */ + xdrawline(line, 0, oy, len); - if (IS_SET(MODE_HIDE)) - return; + 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 | - ATTR_BOXDRAW; + /* + * Select the right color for the right mode. + */ + g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE|ATTR_BOXDRAW; - if (IS_SET(MODE_REVERSE)) { - g.mode |= ATTR_REVERSE; - g.bg = defaultfg; - if (selected(cx, cy)) { - drawcol = dc.col[defaultcs]; - g.fg = defaultrcs; - } else { - drawcol = dc.col[defaultrcs]; - g.fg = defaultcs; - } - } else { - if (selected(cx, cy)) { - g.fg = defaultfg; - g.bg = defaultrcs; - } else { - g.fg = defaultbg; - g.bg = defaultcs; - } - drawcol = dc.col[g.bg]; - } + if (IS_SET(MODE_REVERSE)) { + g.mode |= ATTR_REVERSE; + g.bg = defaultfg; + if (selected(cx, cy)) { + drawcol = dc.col[defaultcs]; + g.fg = defaultrcs; + } else { + drawcol = dc.col[defaultrcs]; + g.fg = defaultcs; + } + } else { + if (selected(cx, cy)) { + g.fg = defaultfg; + g.bg = defaultrcs; + } else { + g.fg = defaultbg; + g.bg = defaultcs; + } + drawcol = dc.col[g.bg]; + } - /* draw the new one */ - if (IS_SET(MODE_FOCUSED)) { - switch (win.cursor) { - case 7: /* st extension */ - g.u = 0x2603; /* snowman (U+2603) */ - /* FALLTHROUGH */ - case 0: /* Blinking Block */ - case 1: /* Blinking Block (Default) */ - case 2: /* Steady Block */ - xdrawglyph(g, cx, cy); - break; - case 3: /* Blinking Underline */ - case 4: /* Steady Underline */ - XftDrawRect(xw.draw, &drawcol, win.hborderpx + cx * win.cw, - win.vborderpx + (cy + 1) * win.ch - cursorthickness, win.cw, - cursorthickness); - break; - case 5: /* Blinking bar */ - case 6: /* Steady bar */ - XftDrawRect(xw.draw, &drawcol, win.hborderpx + cx * win.cw, - win.vborderpx + cy * win.ch, cursorthickness, win.ch); - break; - } - } else { - XftDrawRect(xw.draw, &drawcol, win.hborderpx + cx * win.cw, - win.vborderpx + cy * win.ch, win.cw - 1, 1); - XftDrawRect(xw.draw, &drawcol, win.hborderpx + cx * win.cw, - win.vborderpx + cy * win.ch, 1, win.ch - 1); - XftDrawRect(xw.draw, &drawcol, win.hborderpx + (cx + 1) * win.cw - 1, - win.vborderpx + cy * win.ch, 1, win.ch - 1); - XftDrawRect(xw.draw, &drawcol, win.hborderpx + cx * win.cw, - win.vborderpx + (cy + 1) * win.ch - 1, win.cw, 1); - } + /* draw the new one */ + if (IS_SET(MODE_FOCUSED)) { + switch (win.cursor) { + case 7: /* st extension */ + g.u = 0x2603; /* snowman (U+2603) */ + /* FALLTHROUGH */ + case 0: /* Blinking Block */ + case 1: /* Blinking Block (Default) */ + case 2: /* Steady Block */ + xdrawglyph(g, cx, cy); + break; + case 3: /* Blinking Underline */ + case 4: /* Steady Underline */ + XftDrawRect(xw.draw, &drawcol, + win.hborderpx + cx * win.cw, + win.vborderpx + (cy + 1) * win.ch - \ + cursorthickness, + win.cw, cursorthickness); + break; + case 5: /* Blinking bar */ + case 6: /* Steady bar */ + XftDrawRect(xw.draw, &drawcol, + win.hborderpx + cx * win.cw, + win.vborderpx + cy * win.ch, + cursorthickness, win.ch); + break; + } + } else { + XftDrawRect(xw.draw, &drawcol, + win.hborderpx + cx * win.cw, + win.vborderpx + cy * win.ch, + win.cw - 1, 1); + XftDrawRect(xw.draw, &drawcol, + win.hborderpx + cx * win.cw, + win.vborderpx + cy * win.ch, + 1, win.ch - 1); + XftDrawRect(xw.draw, &drawcol, + win.hborderpx + (cx + 1) * win.cw - 1, + win.vborderpx + cy * win.ch, + 1, win.ch - 1); + XftDrawRect(xw.draw, &drawcol, + win.hborderpx + cx * win.cw, + win.vborderpx + (cy + 1) * win.ch - 1, + win.cw, 1); + } } -void xsetenv(void) { - char buf[sizeof(long) * 8 + 1]; +void +xsetenv(void) +{ + char buf[sizeof(long) * 8 + 1]; - snprintf(buf, sizeof(buf), "%lu", xw.win); - setenv("WINDOWID", buf, 1); + snprintf(buf, sizeof(buf), "%lu", xw.win); + setenv("WINDOWID", buf, 1); } -void xseticontitle(char *p) { - XTextProperty prop; - DEFAULT(p, opt_title); +void +xsettitle(char *p) +{ + XTextProperty prop; + DEFAULT(p, opt_title); - if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle, &prop) != - Success) - return; - XSetWMIconName(xw.dpy, xw.win, &prop); - XSetTextProperty(xw.dpy, xw.win, &prop, xw.netwmiconname); - XFree(prop.value); + Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle, + &prop); + XSetWMName(xw.dpy, xw.win, &prop); + XSetTextProperty(xw.dpy, xw.win, &prop, xw.netwmname); + XFree(prop.value); } -void xsettitle(char *p) { - XTextProperty prop; - DEFAULT(p, opt_title); - - if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle, &prop) != - Success) - return; - XSetWMName(xw.dpy, xw.win, &prop); - XSetTextProperty(xw.dpy, xw.win, &prop, xw.netwmname); - XFree(prop.value); +int +xstartdraw(void) +{ + return IS_SET(MODE_VISIBLE); } -int xstartdraw(void) { return IS_SET(MODE_VISIBLE); } +void +xdrawline(Line line, int x1, int y1, int x2) +{ + int i, x, ox, numspecs; + Glyph base, new; + XftGlyphFontSpec *specs = xw.specbuf; -void xdrawline(Line line, int x1, int y1, int x2) { - int i, x, ox, numspecs; - Glyph base, new; - XftGlyphFontSpec *specs = xw.specbuf; - - numspecs = xmakeglyphfontspecs(specs, &line[x1], x2 - x1, x1, y1); - i = ox = 0; - for (x = x1; x < x2 && i < numspecs; x++) { - new = line[x]; - if (new.mode == ATTR_WDUMMY) - continue; - if (selected(x, y1)) - new.mode ^= ATTR_REVERSE; - if (i > 0 && ATTRCMP(base, new)) { - xdrawglyphfontspecs(specs, base, i, ox, y1); - specs += i; - numspecs -= i; - i = 0; - } - if (i == 0) { - ox = x; - base = new; - } - i++; - } - if (i > 0) - xdrawglyphfontspecs(specs, base, i, ox, y1); + numspecs = xmakeglyphfontspecs(specs, &line[x1], x2 - x1, x1, y1); + i = ox = 0; + for (x = x1; x < x2 && i < numspecs; x++) { + new = line[x]; + if (new.mode == ATTR_WDUMMY) + continue; + if (selected(x, y1)) + new.mode ^= ATTR_REVERSE; + if (i > 0 && ATTRCMP(base, new)) { + xdrawglyphfontspecs(specs, base, i, ox, y1); + specs += i; + numspecs -= i; + i = 0; + } + if (i == 0) { + ox = x; + base = new; + } + i++; + } + if (i > 0) + xdrawglyphfontspecs(specs, base, i, ox, y1); } -void xfinishdraw(void) { - XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, win.w, win.h, 0, 0); - XSetForeground(xw.dpy, dc.gc, - dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg].pixel); +void +xfinishdraw(void) +{ + XCopyArea(xw.dpy, xw.buf, xw.win, dc.gc, 0, 0, win.w, + win.h, 0, 0); + XSetForeground(xw.dpy, dc.gc, + dc.col[IS_SET(MODE_REVERSE)? + defaultfg : defaultbg].pixel); } -void xximspot(int x, int y) { - if (xw.ime.xic == NULL) - return; +void +xximspot(int x, int y) +{ + if (xw.ime.xic == NULL) + return; - xw.ime.spot.x = borderpx + x * win.cw; - xw.ime.spot.y = borderpx + (y + 1) * win.ch; + xw.ime.spot.x = borderpx + x * win.cw; + xw.ime.spot.y = borderpx + (y + 1) * win.ch; - XSetICValues(xw.ime.xic, XNPreeditAttributes, xw.ime.spotlist, NULL); + XSetICValues(xw.ime.xic, XNPreeditAttributes, xw.ime.spotlist, NULL); } -void expose(XEvent *ev) { redraw(); } - -void visibility(XEvent *ev) { - XVisibilityEvent *e = &ev->xvisibility; - - MODBIT(win.mode, e->state != VisibilityFullyObscured, MODE_VISIBLE); +void +expose(XEvent *ev) +{ + redraw(); } -void unmap(XEvent *ev) { win.mode &= ~MODE_VISIBLE; } +void +visibility(XEvent *ev) +{ + XVisibilityEvent *e = &ev->xvisibility; -void xsetpointermotion(int set) { - if (!set && !xw.pointerisvisible) - return; - MODBIT(xw.attrs.event_mask, set, PointerMotionMask); - XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, &xw.attrs); + MODBIT(win.mode, e->state != VisibilityFullyObscured, MODE_VISIBLE); } -void xsetmode(int set, unsigned int flags) { - int mode = win.mode; - MODBIT(win.mode, set, flags); - if ((win.mode & MODE_REVERSE) != (mode & MODE_REVERSE)) - redraw(); +void +unmap(XEvent *ev) +{ + win.mode &= ~MODE_VISIBLE; } -int xsetcursor(int cursor) { - if (!BETWEEN(cursor, 0, 7)) /* 7: st extension */ - return 1; - win.cursor = cursor; - return 0; +void +xsetpointermotion(int set) +{ + if (!set && !xw.pointerisvisible) + return; + MODBIT(xw.attrs.event_mask, set, PointerMotionMask); + XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, &xw.attrs); } -void xseturgency(int add) { - XWMHints *h = XGetWMHints(xw.dpy, xw.win); - - MODBIT(h->flags, add, XUrgencyHint); - XSetWMHints(xw.dpy, xw.win, h); - XFree(h); +void +xsetmode(int set, unsigned int flags) +{ + int mode = win.mode; + MODBIT(win.mode, set, flags); + if ((win.mode & MODE_REVERSE) != (mode & MODE_REVERSE)) + redraw(); } -void xbell(void) { - if (!(IS_SET(MODE_FOCUSED))) - xseturgency(1); - if (bellvolume) - XkbBell(xw.dpy, xw.win, bellvolume, (Atom)NULL); +int +xsetcursor(int cursor) +{ + if (!BETWEEN(cursor, 0, 7)) /* 7: st extension */ + return 1; + win.cursor = cursor; + return 0; } -void focus(XEvent *ev) { - XFocusChangeEvent *e = &ev->xfocus; +void +xseturgency(int add) +{ + XWMHints *h = XGetWMHints(xw.dpy, xw.win); - if (e->mode == NotifyGrab) - return; - - if (ev->type == FocusIn) { - if (xw.ime.xic) - XSetICFocus(xw.ime.xic); - win.mode |= MODE_FOCUSED; - xseturgency(0); - if (IS_SET(MODE_FOCUS)) - ttywrite("\033[I", 3, 0); - } else { - if (xw.ime.xic) - XUnsetICFocus(xw.ime.xic); - win.mode &= ~MODE_FOCUSED; - if (IS_SET(MODE_FOCUS)) - ttywrite("\033[O", 3, 0); - } + MODBIT(h->flags, add, XUrgencyHint); + XSetWMHints(xw.dpy, xw.win, h); + XFree(h); } -int match(uint mask, uint state) { - return mask == XK_ANY_MOD || mask == (state & ~ignoremod); +void +xbell(void) +{ + if (!(IS_SET(MODE_FOCUSED))) + xseturgency(1); + if (bellvolume) + XkbBell(xw.dpy, xw.win, bellvolume, (Atom)NULL); } -char *kmap(KeySym k, uint state) { - Key *kp; - int i; +void +focus(XEvent *ev) +{ + XFocusChangeEvent *e = &ev->xfocus; - /* Check for mapped keys out of X11 function keys. */ - for (i = 0; i < LEN(mappedkeys); i++) { - if (mappedkeys[i] == k) - break; - } - if (i == LEN(mappedkeys)) { - if ((k & 0xFFFF) < 0xFD00) - return NULL; - } + if (e->mode == NotifyGrab) + return; - for (kp = key; kp < key + LEN(key); kp++) { - if (kp->k != k) - continue; - - if (!match(kp->mask, state)) - continue; - - if (IS_SET(MODE_APPKEYPAD) ? kp->appkey < 0 : kp->appkey > 0) - continue; - if (IS_SET(MODE_NUMLOCK) && kp->appkey == 2) - continue; - - if (IS_SET(MODE_APPCURSOR) ? kp->appcursor < 0 : kp->appcursor > 0) - continue; - - return kp->s; - } - - return NULL; + if (ev->type == FocusIn) { + if (xw.ime.xic) + XSetICFocus(xw.ime.xic); + win.mode |= MODE_FOCUSED; + xseturgency(0); + if (IS_SET(MODE_FOCUS)) + ttywrite("\033[I", 3, 0); + } else { + if (xw.ime.xic) + XUnsetICFocus(xw.ime.xic); + win.mode &= ~MODE_FOCUSED; + if (IS_SET(MODE_FOCUS)) + ttywrite("\033[O", 3, 0); + } } -void cmessage(XEvent *e) { - /* - * See xembed specs - * http://standards.freedesktop.org/xembed-spec/xembed-spec-latest.html - */ - if (e->xclient.message_type == xw.xembed && e->xclient.format == 32) { - if (e->xclient.data.l[1] == XEMBED_FOCUS_IN) { - win.mode |= MODE_FOCUSED; - xseturgency(0); - } else if (e->xclient.data.l[1] == XEMBED_FOCUS_OUT) { - win.mode &= ~MODE_FOCUSED; - } - } else if (e->xclient.data.l[0] == xw.wmdeletewin) { - ttyhangup(); - exit(0); - } +int +match(uint mask, uint state) +{ + return mask == XK_ANY_MOD || mask == (state & ~ignoremod); +} + +char* +kmap(KeySym k, uint state) +{ + Key *kp; + int i; + + /* Check for mapped keys out of X11 function keys. */ + for (i = 0; i < LEN(mappedkeys); i++) { + if (mappedkeys[i] == k) + break; + } + if (i == LEN(mappedkeys)) { + if ((k & 0xFFFF) < 0xFD00) + return NULL; + } + + for (kp = key; kp < key + LEN(key); kp++) { + if (kp->k != k) + continue; + + if (!match(kp->mask, state)) + continue; + + if (IS_SET(MODE_APPKEYPAD) ? kp->appkey < 0 : kp->appkey > 0) + continue; + if (IS_SET(MODE_NUMLOCK) && kp->appkey == 2) + continue; + + if (IS_SET(MODE_APPCURSOR) ? kp->appcursor < 0 : kp->appcursor > 0) + continue; + + return kp->s; + } + + return NULL; } void kpress(XEvent *ev) { XKeyEvent *e = &ev->xkey; - KeySym ksym = NoSymbol; + KeySym ksym; char buf[64], *customkey; int len; Rune c; Status status; Shortcut *bp; - if (xw.pointerisvisible) { - XDefineCursor(xw.dpy, xw.win, xw.bpointer); - xsetpointermotion(1); - xw.pointerisvisible = 0; - } + if (xw.pointerisvisible) { + XDefineCursor(xw.dpy, xw.win, xw.bpointer); + xsetpointermotion(1); + xw.pointerisvisible = 0; + } if (IS_SET(MODE_KBDLOCK)) return; - if (xw.ime.xic) { + if (xw.ime.xic) len = XmbLookupString(xw.ime.xic, e, buf, sizeof buf, &ksym, &status); - if (status == XBufferOverflow) - return; - } else { + else len = XLookupString(e, buf, sizeof buf, &ksym, NULL); - } /* 1. shortcuts */ for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) { if (ksym == bp->keysym && match(bp->mod, e->state)) { @@ -1899,193 +2025,221 @@ kpress(XEvent *ev) ttywrite(buf, len, 1); } -void resize(XEvent *e) { - if (e->xconfigure.width == win.w && e->xconfigure.height == win.h) - return; - - cresize(e->xconfigure.width, e->xconfigure.height); +void +cmessage(XEvent *e) +{ + /* + * See xembed specs + * http://standards.freedesktop.org/xembed-spec/xembed-spec-latest.html + */ + if (e->xclient.message_type == xw.xembed && e->xclient.format == 32) { + if (e->xclient.data.l[1] == XEMBED_FOCUS_IN) { + win.mode |= MODE_FOCUSED; + xseturgency(0); + } else if (e->xclient.data.l[1] == XEMBED_FOCUS_OUT) { + win.mode &= ~MODE_FOCUSED; + } + } else if (e->xclient.data.l[0] == xw.wmdeletewin) { + ttyhangup(); + exit(0); + } } -void run(void) { - XEvent ev; - int w = win.w, h = win.h; - fd_set rfd; - int xfd = XConnectionNumber(xw.dpy), ttyfd, xev, drawing; - struct timespec seltv, *tv, now, lastblink, trigger; - double timeout; +void +resize(XEvent *e) +{ + if (e->xconfigure.width == win.w && e->xconfigure.height == win.h) + return; - /* Waiting for window mapping */ - do { - XNextEvent(xw.dpy, &ev); - /* - * This XFilterEvent call is required because of XOpenIM. It - * does filter out the key event and some client message for - * the input method too. - */ - if (XFilterEvent(&ev, None)) - continue; - if (ev.type == ConfigureNotify) { - w = ev.xconfigure.width; - h = ev.xconfigure.height; - } - } while (ev.type != MapNotify); - - ttyfd = ttynew(opt_line, shell, opt_io, opt_cmd); - cresize(w, h); - - for (timeout = -1, drawing = 0, lastblink = (struct timespec){0};;) { - FD_ZERO(&rfd); - FD_SET(ttyfd, &rfd); - FD_SET(xfd, &rfd); - - if (XPending(xw.dpy)) - timeout = 0; /* existing events might not set xfd */ - - seltv.tv_sec = timeout / 1E3; - seltv.tv_nsec = 1E6 * (timeout - 1E3 * seltv.tv_sec); - tv = timeout >= 0 ? &seltv : NULL; - - if (pselect(MAX(xfd, ttyfd) + 1, &rfd, NULL, NULL, tv, NULL) < 0) { - if (errno == EINTR) - continue; - die("select failed: %s\n", strerror(errno)); - } - clock_gettime(CLOCK_MONOTONIC, &now); - - if (FD_ISSET(ttyfd, &rfd)) - ttyread(); - - xev = 0; - while (XPending(xw.dpy)) { - xev = 1; - XNextEvent(xw.dpy, &ev); - if (XFilterEvent(&ev, None)) - continue; - if (handler[ev.type]) - (handler[ev.type])(&ev); - } - - /* - * To reduce flicker and tearing, when new content or event - * triggers drawing, we first wait a bit to ensure we got - * everything, and if nothing new arrives - we draw. - * We start with trying to wait minlatency ms. If more content - * arrives sooner, we retry with shorter and shorter periods, - * and eventually draw even without idle after maxlatency ms. - * Typically this results in low latency while interacting, - * maximum latency intervals during `cat huge.txt`, and perfect - * sync with periodic updates from animations/key-repeats/etc. - */ - if (FD_ISSET(ttyfd, &rfd) || xev) { - if (!drawing) { - trigger = now; - drawing = 1; - } - timeout = (maxlatency - TIMEDIFF(now, trigger)) / maxlatency * minlatency; - if (timeout > 0) - continue; /* we have time, try to find idle */ - } - - /* idle detected or maxlatency exhausted -> draw */ - timeout = -1; - if (blinktimeout && tattrset(ATTR_BLINK)) { - timeout = blinktimeout - TIMEDIFF(now, lastblink); - if (timeout <= 0) { - if (-timeout > blinktimeout) /* start visible */ - win.mode |= MODE_BLINK; - win.mode ^= MODE_BLINK; - tsetdirtattr(ATTR_BLINK); - lastblink = now; - timeout = blinktimeout; - } - } - - draw(); - XFlush(xw.dpy); - drawing = 0; - } + cresize(e->xconfigure.width, e->xconfigure.height); } -void usage(void) { - die("usage: %s [-aiv] [-c class] [-f font] [-g geometry]" - " [-n name] [-o file]\n" - " [-T title] [-t title] [-w windowid]" - " [[-e] command [args ...]]\n" - " %s [-aiv] [-c class] [-f font] [-g geometry]" - " [-n name] [-o file]\n" - " [-T title] [-t title] [-w windowid] -l line" - " [stty_args ...]\n", - argv0, argv0); +void +run(void) +{ + XEvent ev; + int w = win.w, h = win.h; + fd_set rfd; + int xfd = XConnectionNumber(xw.dpy), ttyfd, xev, drawing; + struct timespec seltv, *tv, now, lastblink, trigger; + double timeout; + + /* Waiting for window mapping */ + do { + XNextEvent(xw.dpy, &ev); + /* + * This XFilterEvent call is required because of XOpenIM. It + * does filter out the key event and some client message for + * the input method too. + */ + if (XFilterEvent(&ev, None)) + continue; + if (ev.type == ConfigureNotify) { + w = ev.xconfigure.width; + h = ev.xconfigure.height; + } + } while (ev.type != MapNotify); + + ttyfd = ttynew(opt_line, shell, opt_io, opt_cmd); + cresize(w, h); + + for (timeout = -1, drawing = 0, lastblink = (struct timespec){0};;) { + FD_ZERO(&rfd); + FD_SET(ttyfd, &rfd); + FD_SET(xfd, &rfd); + + if (XPending(xw.dpy)) + timeout = 0; /* existing events might not set xfd */ + + seltv.tv_sec = timeout / 1E3; + seltv.tv_nsec = 1E6 * (timeout - 1E3 * seltv.tv_sec); + tv = timeout >= 0 ? &seltv : NULL; + + if (pselect(MAX(xfd, ttyfd)+1, &rfd, NULL, NULL, tv, NULL) < 0) { + if (errno == EINTR) + continue; + die("select failed: %s\n", strerror(errno)); + } + clock_gettime(CLOCK_MONOTONIC, &now); + + if (FD_ISSET(ttyfd, &rfd)) + ttyread(); + + xev = 0; + while (XPending(xw.dpy)) { + xev = 1; + XNextEvent(xw.dpy, &ev); + if (XFilterEvent(&ev, None)) + continue; + if (handler[ev.type]) + (handler[ev.type])(&ev); + } + + /* + * To reduce flicker and tearing, when new content or event + * triggers drawing, we first wait a bit to ensure we got + * everything, and if nothing new arrives - we draw. + * We start with trying to wait minlatency ms. If more content + * arrives sooner, we retry with shorter and shorter periods, + * and eventually draw even without idle after maxlatency ms. + * Typically this results in low latency while interacting, + * maximum latency intervals during `cat huge.txt`, and perfect + * sync with periodic updates from animations/key-repeats/etc. + */ + if (FD_ISSET(ttyfd, &rfd) || xev) { + if (!drawing) { + trigger = now; + drawing = 1; + } + timeout = (maxlatency - TIMEDIFF(now, trigger)) \ + / maxlatency * minlatency; + if (timeout > 0) + continue; /* we have time, try to find idle */ + } + + /* idle detected or maxlatency exhausted -> draw */ + timeout = -1; + if (blinktimeout && tattrset(ATTR_BLINK)) { + timeout = blinktimeout - TIMEDIFF(now, lastblink); + if (timeout <= 0) { + if (-timeout > blinktimeout) /* start visible */ + win.mode |= MODE_BLINK; + win.mode ^= MODE_BLINK; + tsetdirtattr(ATTR_BLINK); + lastblink = now; + timeout = blinktimeout; + } + } + + draw(); + XFlush(xw.dpy); + drawing = 0; + } } -int main(int argc, char *argv[]) { - xw.l = xw.t = 0; - xw.isfixed = False; - xsetcursor(cursorshape); +void +usage(void) +{ + die("usage: %s [-aiv] [-c class] [-f font] [-g geometry]" + " [-n name] [-o file]\n" + " [-T title] [-t title] [-w windowid]" + " [[-e] command [args ...]]\n" + " %s [-aiv] [-c class] [-f font] [-g geometry]" + " [-n name] [-o file]\n" + " [-T title] [-t title] [-w windowid] -l line" + " [stty_args ...]\n", argv0, argv0); +} - ARGBEGIN { - case 'a': - allowaltscreen = 0; - break; - case 'A': - opt_alpha = EARGF(usage()); - break; - case 'c': - opt_class = EARGF(usage()); - break; - case 'e': - if (argc > 0) - --argc, ++argv; - goto run; - case 'f': - opt_font = EARGF(usage()); - break; - case 'g': - xw.gm = XParseGeometry(EARGF(usage()), &xw.l, &xw.t, &cols, &rows); - break; - case 'i': - xw.isfixed = 1; - break; - case 'o': - opt_io = EARGF(usage()); - break; - case 'l': - opt_line = EARGF(usage()); - break; - case 'n': - opt_name = EARGF(usage()); - break; - case 't': - case 'T': - opt_title = EARGF(usage()); - break; - case 'w': - opt_embed = EARGF(usage()); - break; - case 'v': - die("%s " VERSION "\n", argv0); - break; - default: - usage(); - } - ARGEND; +int +main(int argc, char *argv[]) +{ + xw.l = xw.t = 0; + xw.isfixed = False; + xsetcursor(cursorshape); + + ARGBEGIN { + case 'a': + allowaltscreen = 0; + break; + case 'A': + opt_alpha = EARGF(usage()); + break; + case 'c': + opt_class = EARGF(usage()); + break; + case 'e': + if (argc > 0) + --argc, ++argv; + goto run; + case 'f': + opt_font = EARGF(usage()); + break; + case 'g': + xw.gm = XParseGeometry(EARGF(usage()), + &xw.l, &xw.t, &cols, &rows); + break; + case 'i': + xw.isfixed = 1; + break; + case 'o': + opt_io = EARGF(usage()); + break; + case 'l': + opt_line = EARGF(usage()); + break; + case 'n': + opt_name = EARGF(usage()); + break; + case 't': + case 'T': + opt_title = EARGF(usage()); + break; + case 'w': + opt_embed = EARGF(usage()); + break; + case 'v': + die("%s " VERSION "\n", argv0); + break; + default: + usage(); + } ARGEND; run: - if (argc > 0) /* eat all remaining arguments */ - opt_cmd = argv; + if (argc > 0) /* eat all remaining arguments */ + opt_cmd = argv; - if (!opt_title) - opt_title = (opt_line || !opt_cmd) ? "st" : opt_cmd[0]; + if (!opt_title) + opt_title = (opt_line || !opt_cmd) ? "st" : opt_cmd[0]; - setlocale(LC_CTYPE, ""); - XSetLocaleModifiers(""); - cols = MAX(cols, 1); - rows = MAX(rows, 1); - tnew(cols, rows); - xinit(cols, rows); - xsetenv(); - selinit(); - run(); + setlocale(LC_CTYPE, ""); + XSetLocaleModifiers(""); + cols = MAX(cols, 1); + rows = MAX(rows, 1); + tnew(cols, rows); + xinit(cols, rows); + xsetenv(); + selinit(); + run(); - return 0; + return 0; }