feat: new version of st with scrollwheel sup

master
Toerd@archlinux 5 years ago
parent 2e2895a8a6
commit abd783625b

@ -1,6 +1,6 @@
## Why does st not handle utmp entries? ## Why does st not handle utmp entries?
Use the excellent tool of [utmp](http://git.suckless.org/utmp/) for this task. Use the excellent tool of [utmp](https://git.suckless.org/utmp/) for this task.
## Some _random program_ complains that st is unknown/not recognised/unsupported/whatever! ## Some _random program_ complains that st is unknown/not recognised/unsupported/whatever!
@ -15,13 +15,6 @@ you can manually run `tic -sx st.info`.
* Some programs dont complain about the lacking st description and default to * Some programs dont complain about the lacking st description and default to
another terminal. In that case see the question about terminfo. another terminal. In that case see the question about terminfo.
## I get some weird glitches/visual bug on _random program_!
Try launching it with a different TERM: $ TERM=xterm myapp. toe(1) will give
you a list of available terminals, but youll most likely switch between xterm,
st or st-256color. The default value for TERM can be changed in config.h
(TNAME).
## How do I scroll back up? ## How do I scroll back up?
Using a terminal multiplexer. Using a terminal multiplexer.
@ -104,7 +97,7 @@ St is emulating the Linux way of handling backspace being delete and delete bein
backspace. backspace.
This is an issue that was discussed in suckless mailing list This is an issue that was discussed in suckless mailing list
<http://lists.suckless.org/dev/1404/20697.html>. Here is why some old grumpy <https://lists.suckless.org/dev/1404/20697.html>. Here is why some old grumpy
terminal users wants its backspace to be how he feels it: terminal users wants its backspace to be how he feels it:
Well, I am going to comment why I want to change the behaviour Well, I am going to comment why I want to change the behaviour
@ -163,5 +156,40 @@ terminal users wants its backspace to be how he feels it:
Apply [1]. Apply [1].
[1] http://st.suckless.org/patches/delkey [1] https://st.suckless.org/patches/delkey
## Why do images not work in st (in programs such as w3m)?
This is a terrible hack that overdraws an image on top of the terminal emulator
window. It also relies on a very specific way the terminal draws it's contents.
A more proper (but limited way) would be using sixels. Which st doesn't
support.
## BadLength X error in Xft when trying to render emoji
Xft makes st crash when rendering color emojis with the following error:
"X Error of failed request: BadLength (poly request too large or internal Xlib length error)"
Major opcode of failed request: 139 (RENDER)
Minor opcode of failed request: 20 (RenderAddGlyphs)
Serial number of failed request: 1595
Current serial number in output stream: 1818"
This is a known bug in Xft (not st) which happens on some platforms and
combination of particular fonts and fontconfig settings.
See also:
https://gitlab.freedesktop.org/xorg/lib/libxft/issues/6
https://bugs.freedesktop.org/show_bug.cgi?id=107534
https://bugzilla.redhat.com/show_bug.cgi?id=1498269
The solution is to remove color emoji fonts or disable this in the fontconfig
XML configuration. As an ugly workaround (which may work only on newer
fontconfig versions (FC_COLOR)), the following code can be used to mask color
fonts:
FcPatternAddBool(fcpattern, FC_COLOR, FcFalse);
Please don't bother reporting this bug to st, but notify the upstream Xft
developers about fixing this bug.

@ -22,7 +22,7 @@ config.h:
$(CC) $(STCFLAGS) -c $< $(CC) $(STCFLAGS) -c $<
st.o: config.h st.h win.h st.o: config.h st.h win.h
x.o: arg.h st.h win.h x.o: arg.h config.h st.h win.h
$(OBJ): config.h config.mk $(OBJ): config.h config.mk

@ -30,9 +30,9 @@ static float chscale = 1.0;
/* /*
* word delimiter string * word delimiter string
* *
* More advanced example: " `'\"()[]{}" * More advanced example: L" `'\"()[]{}"
*/ */
char *worddelimiters = " "; wchar_t *worddelimiters = L" ";
/* selection timeouts (in milliseconds) */ /* selection timeouts (in milliseconds) */
static unsigned int doubleclicktimeout = 300; static unsigned int doubleclicktimeout = 300;
@ -82,9 +82,6 @@ char *termname = "st-256color";
*/ */
unsigned int tabspaces = 8; unsigned int tabspaces = 8;
/* bg opacity */
unsigned int alpha = 0xcc;
/* Terminal colors (16 first used in escape sequence) */ /* Terminal colors (16 first used in escape sequence) */
static const char *colorname[] = { static const char *colorname[] = {
/* 8 normal colors */ /* 8 normal colors */
@ -112,7 +109,6 @@ static const char *colorname[] = {
/* more colors can be added after 255 to use with DefaultXX */ /* more colors can be added after 255 to use with DefaultXX */
"#cccccc", "#cccccc",
"#555555", "#555555",
"black",
}; };
@ -121,7 +117,7 @@ static const char *colorname[] = {
* foreground, background, cursor, reverse cursor * foreground, background, cursor, reverse cursor
*/ */
unsigned int defaultfg = 7; unsigned int defaultfg = 7;
unsigned int defaultbg = 257; unsigned int defaultbg = 0;
static unsigned int defaultcs = 256; static unsigned int defaultcs = 256;
static unsigned int defaultrcs = 257; static unsigned int defaultrcs = 257;
@ -154,14 +150,24 @@ static unsigned int mousebg = 0;
*/ */
static unsigned int defaultattr = 11; static unsigned int defaultattr = 11;
/*
* Force mouse select/shortcuts while mask is active (when MODE_MOUSE is set).
* Note that if you want to use ShiftMask with selmasks, set this to an other
* modifier, set to 0 to not use it.
*/
static uint forcemousemod = ShiftMask;
/* /*
* Internal mouse shortcuts. * Internal mouse shortcuts.
* Beware that overloading Button1 will disable the selection. * Beware that overloading Button1 will disable the selection.
*/ */
static MouseShortcut mshortcuts[] = { static MouseShortcut mshortcuts[] = {
/* button mask string */ /* mask button function argument release */
{ Button4, XK_ANY_MOD, "\031" }, { ShiftMask, Button4, kscrollup, {.i = 1} },
{ Button5, XK_ANY_MOD, "\005" }, { ShiftMask, Button5, kscrolldown, {.i = 1} },
{ XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 },
{ XK_ANY_MOD, Button4, ttysend, {.s = "\031"} },
{ XK_ANY_MOD, Button5, ttysend, {.s = "\005"} },
}; };
/* Internal keyboard shortcuts. */ /* Internal keyboard shortcuts. */
@ -180,8 +186,8 @@ static Shortcut shortcuts[] = {
{ TERMMOD, XK_C, clipcopy, {.i = 0} }, { TERMMOD, XK_C, clipcopy, {.i = 0} },
{ TERMMOD, XK_V, clippaste, {.i = 0} }, { TERMMOD, XK_V, clippaste, {.i = 0} },
{ TERMMOD, XK_Y, selpaste, {.i = 0} }, { TERMMOD, XK_Y, selpaste, {.i = 0} },
{ ShiftMask, XK_Insert, selpaste, {.i = 0} },
{ TERMMOD, XK_Num_Lock, numlock, {.i = 0} }, { TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
{ TERMMOD, XK_I, iso14755, {.i = 0} },
{ ShiftMask, XK_Page_Up, kscrollup, {.i = -1} }, { ShiftMask, XK_Page_Up, kscrollup, {.i = -1} },
{ ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} }, { ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} },
}; };
@ -201,10 +207,6 @@ static Shortcut shortcuts[] = {
* * 0: no value * * 0: no value
* * > 0: cursor application mode enabled * * > 0: cursor application mode enabled
* * < 0: cursor application mode disabled * * < 0: cursor application mode disabled
* crlf value
* * 0: no value
* * > 0: crlf mode is enabled
* * < 0: crlf mode is disabled
* *
* Be careful with the order of the definitions because st searches in * Be careful with the order of the definitions because st searches in
* this table sequentially, so any XK_ANY_MOD must be in the last * this table sequentially, so any XK_ANY_MOD must be in the last
@ -223,13 +225,6 @@ static KeySym mappedkeys[] = { -1 };
*/ */
static uint ignoremod = Mod2Mask|XK_SWITCH_MOD; static uint ignoremod = Mod2Mask|XK_SWITCH_MOD;
/*
* Override mouse-select while mask is active (when MODE_MOUSE is set).
* Note that if you want to use ShiftMask with selmasks, set this to an other
* modifier, set to 0 to not use it.
*/
static uint forceselmod = ShiftMask;
/* /*
* This is the huge key array which defines all compatibility to the Linux * This is the huge key array which defines all compatibility to the Linux
* world. Please decide about changes wisely. * world. Please decide about changes wisely.

@ -5,8 +5,8 @@
* *
* font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html * font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html
*/ */
static char *font = "Iosevka:pixelsize=20:antialias=true:autohint=true"; static char *font = "Cozette:antialias=true:autohint=true";
static int borderpx = 2; static int borderpx = 0;
/* /*
* What program is execed by st depends of these precedence rules: * What program is execed by st depends of these precedence rules:
@ -16,7 +16,7 @@ static int borderpx = 2;
* 4: value of shell in /etc/passwd * 4: value of shell in /etc/passwd
* 5: value of shell in config.h * 5: value of shell in config.h
*/ */
static char *shell = "/bin/bash"; static char *shell = "/bin/sh";
char *utmp = NULL; char *utmp = NULL;
char *stty_args = "stty raw pass8 nl -echo -iexten -cstopb 38400"; char *stty_args = "stty raw pass8 nl -echo -iexten -cstopb 38400";
@ -30,9 +30,9 @@ static float chscale = 1.0;
/* /*
* word delimiter string * word delimiter string
* *
* More advanced example: " `'\"()[]{}" * More advanced example: L" `'\"()[]{}"
*/ */
char *worddelimiters = " "; wchar_t *worddelimiters = L" ";
/* selection timeouts (in milliseconds) */ /* selection timeouts (in milliseconds) */
static unsigned int doubleclicktimeout = 300; static unsigned int doubleclicktimeout = 300;
@ -82,59 +82,47 @@ char *termname = "st-256color";
*/ */
unsigned int tabspaces = 8; unsigned int tabspaces = 8;
/* bg opacity */ /* Terminal colors (16 first used in escape sequence) */
unsigned int alpha = 0xee;
static const char *colorname[] = { static const char *colorname[] = {
/* 8 normal colors */
[0] = "#282828", /* black */
[1] = "#fb4934", /* red */
[2] = "#b8bb26", /* green */
[3] = "#fabd2f", /* yellow */
[4] = "#83a599", /* blue */
[5] = "#d3869b", /* magenta */
[6] = "#17ccd5", /* cyan */
[7] = "#fdf4c1", /* white */
/* 8 bright colors */
[8] = "#504945", /* black */
[9] = "#fb4933", /* red */
[10] = "#73af00", /* green */
[11] = "#fabd2f", /* yellow */
[12] = "#83a598", /* blue */
[13] = "#d3869b", /* magenta */
[14] = "#17ccd5", /* cyan */
[15] = "#ffffc8", /* white */
};
const char *altcolorname[] = {
/* 8 normal colors */ /* 8 normal colors */
[0] = "#fafafa", /* black */ [0] = "#1d1f21", /* black */
[1] = "#ad1457", /* red */ [1] = "#cc6666", /* red */
[2] = "#26a69a", /* green */ [2] = "#b5bd68", /* green */
[3] = "#ad1457", /* yellow */ [3] = "#f0c674", /* yellow */
[4] = "#81d4fa", /* blue */ [4] = "#81a2be", /* blue */
[5] = "#ad1457", /* magenta */ [5] = "#b294bb", /* magenta */
[6] = "#26a69a", /* cyan */ [6] = "#8abeb7", /* cyan */
[7] = "#cfd8dc", /* white */ [7] = "#c5c8c6", /* white */
/* 8 bright colors */ /* 8 bright colors */
[8] = "#37474f", /* black */ [8] = "#969896", /* black */
[9] = "#e91e63", /* red */ [9] = "#cc6666", /* red */
[10] = "#8bc34a", /* green */ [10] = "#b5bd68", /* green */
[11] = "#e91e63", /* yellow */ [11] = "#f0c674", /* yellow */
[12] = "#03a9f4", /* blue */ [12] = "#81a2be", /* blue */
[13] = "#e91e63", /* magenta */ [13] = "#b294bb", /* magenta */
[14] = "#009688", /* cyan */ [14] = "#8abeb7", /* cyan */
[15] = "#263238", /* white */ [15] = "#ffffff", /* white */
/* special colors */
[256] = "#1d1f21", /* background */
[257] = "#c5c8c6", /* foreground */
}; };
unsigned int defaultfg = 15; /*
unsigned int defaultbg = 0; * Default colors (colorname index)
static unsigned int defaultcs = 14; * foreground, background, cursor
static unsigned int defaultrcs = 15; */
unsigned int defaultfg = 257;
unsigned int defaultbg = 256;
static unsigned int defaultcs = 257;
static unsigned int defaultrcs = 256;
/*
* Colors used, when the specific fg == defaultfg. So in reverse mode this
* will reverse too. Another logic would only make the simple feature too
* complex.
*/
static unsigned int defaultitalic = 7; static unsigned int defaultitalic = 7;
static unsigned int defaultunderline = 7; static unsigned int defaultunderline = 7;
@ -167,14 +155,24 @@ static unsigned int mousebg = 0;
*/ */
static unsigned int defaultattr = 11; static unsigned int defaultattr = 11;
/*
* Force mouse select/shortcuts while mask is active (when MODE_MOUSE is set).
* Note that if you want to use ShiftMask with selmasks, set this to an other
* modifier, set to 0 to not use it.
*/
static uint forcemousemod = ShiftMask;
/* /*
* Internal mouse shortcuts. * Internal mouse shortcuts.
* Beware that overloading Button1 will disable the selection. * Beware that overloading Button1 will disable the selection.
*/ */
static MouseShortcut mshortcuts[] = { static MouseShortcut mshortcuts[] = {
/* button mask string */ /* mask button function argument release */
{Button4, XK_ANY_MOD, "\031"}, { Mod1Mask, Button4, kscrollup, {.i = 1} },
{Button5, XK_ANY_MOD, "\005"}, { Mod1Mask, Button5, kscrolldown, {.i = 1} },
{ XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 },
{ XK_ANY_MOD, Button4, ttysend, {.s = "\031"} },
{ XK_ANY_MOD, Button5, ttysend, {.s = "\005"} },
}; };
/* Internal keyboard shortcuts. */ /* Internal keyboard shortcuts. */
@ -193,12 +191,10 @@ static Shortcut shortcuts[] = {
{ TERMMOD, XK_C, clipcopy, {.i = 0} }, { TERMMOD, XK_C, clipcopy, {.i = 0} },
{ TERMMOD, XK_V, clippaste, {.i = 0} }, { TERMMOD, XK_V, clippaste, {.i = 0} },
{ TERMMOD, XK_Y, selpaste, {.i = 0} }, { TERMMOD, XK_Y, selpaste, {.i = 0} },
{ ShiftMask, XK_Insert, selpaste, {.i = 0} },
{ TERMMOD, XK_Num_Lock, numlock, {.i = 0} }, { TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
{TERMMOD, XK_I, iso14755, {.i = 0}},
{ ShiftMask, XK_Page_Up, kscrollup, {.i = -1} }, { ShiftMask, XK_Page_Up, kscrollup, {.i = -1} },
{ ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} }, { ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} },
{XK_ANY_MOD, XK_F9, swapcolors, {.i = 0}},
}; };
/* /*
@ -216,10 +212,6 @@ static Shortcut shortcuts[] = {
* * 0: no value * * 0: no value
* * > 0: cursor application mode enabled * * > 0: cursor application mode enabled
* * < 0: cursor application mode disabled * * < 0: cursor application mode disabled
* crlf value
* * 0: no value
* * > 0: crlf mode is enabled
* * < 0: crlf mode is disabled
* *
* Be careful with the order of the definitions because st searches in * Be careful with the order of the definitions because st searches in
* this table sequentially, so any XK_ANY_MOD must be in the last * this table sequentially, so any XK_ANY_MOD must be in the last
@ -238,13 +230,6 @@ static KeySym mappedkeys[] = {-1};
*/ */
static uint ignoremod = Mod2Mask|XK_SWITCH_MOD; static uint ignoremod = Mod2Mask|XK_SWITCH_MOD;
/*
* Override mouse-select while mask is active (when MODE_MOUSE is set).
* Note that if you want to use ShiftMask with selmasks, set this to an other
* modifier, set to 0 to not use it.
*/
static uint forceselmod = ShiftMask;
/* /*
* This is the huge key array which defines all compatibility to the Linux * This is the huge key array which defines all compatibility to the Linux
* world. Please decide about changes wisely. * world. Please decide about changes wisely.
@ -477,6 +462,7 @@ static uint selmasks[] = {
* Printable characters in ASCII, used to estimate the advance width * Printable characters in ASCII, used to estimate the advance width
* of single wide characters. * of single wide characters.
*/ */
static char ascii_printable[] = " !\"#$%&'()*+,-./0123456789:;<=>?" static char ascii_printable[] =
" !\"#$%&'()*+,-./0123456789:;<=>?"
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
"`abcdefghijklmnopqrstuvwxyz{|}~"; "`abcdefghijklmnopqrstuvwxyz{|}~";

@ -1,5 +1,5 @@
# st version # st version
VERSION = 0.8.1 VERSION = 0.8.2
# Customize below to fit your system # Customize below to fit your system
@ -10,19 +10,26 @@ MANPREFIX = $(PREFIX)/share/man
X11INC = /usr/X11R6/include X11INC = /usr/X11R6/include
X11LIB = /usr/X11R6/lib X11LIB = /usr/X11R6/lib
PKG_CONFIG = pkg-config
# includes and libs # includes and libs
INCS = -I. -I/usr/include -I${X11INC} \ INCS = -I$(X11INC) \
`pkg-config --cflags fontconfig` \ `$(PKG_CONFIG) --cflags fontconfig` \
`pkg-config --cflags freetype2` `$(PKG_CONFIG) --cflags freetype2`
LIBS = -L/usr/lib -lc -L${X11LIB} -lm -lrt -lX11 -lutil -lXft -lXrender\ LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft \
`pkg-config --libs fontconfig` \ `$(PKG_CONFIG) --libs fontconfig` \
`pkg-config --libs freetype2` `$(PKG_CONFIG) --libs freetype2`
# flags # flags
CPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600 STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600
STCFLAGS = $(INCS) $(CPPFLAGS) $(CFLAGS) STCFLAGS = $(INCS) $(STCPPFLAGS) $(CPPFLAGS) $(CFLAGS)
STLDFLAGS = $(LIBS) $(LDFLAGS) 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`
# compiler and linker # compiler and linker
# CC = c99 # CC = c99

@ -159,10 +159,6 @@ Copy the selected text to the clipboard selection.
.TP .TP
.B Ctrl-Shift-v .B Ctrl-Shift-v
Paste from the clipboard selection. Paste from the clipboard selection.
.TP
.B Ctrl-Shift-i
Launch dmenu to enter a unicode codepoint and send the corresponding glyph
to st.
.SH CUSTOMIZATION .SH CUSTOMIZATION
.B st .B st
can be customized by creating a custom config.h and (re)compiling the source can be customized by creating a custom config.h and (re)compiling the source

@ -35,17 +35,17 @@
#define ESC_ARG_SIZ 16 #define ESC_ARG_SIZ 16
#define STR_BUF_SIZ ESC_BUF_SIZ #define STR_BUF_SIZ ESC_BUF_SIZ
#define STR_ARG_SIZ ESC_ARG_SIZ #define STR_ARG_SIZ ESC_ARG_SIZ
#define HISTSIZE 2000
/* macros */ /* macros */
#define IS_SET(flag) ((term.mode & (flag)) != 0) #define IS_SET(flag) ((term.mode & (flag)) != 0)
#define NUMMAXLEN(x) ((int)(sizeof(x) * 2.56 + 0.5) + 1)
#define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f) || (c) == '\177') #define ISCONTROLC0(c) (BETWEEN(c, 0, 0x1f) || (c) == '\177')
#define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f)) #define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f))
#define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c)) #define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c))
#define ISDELIM(u) (utf8strchr(worddelimiters, u) != NULL) #define ISDELIM(u) (u && wcschr(worddelimiters, u))
#define TLINE(y) ((y) < term.scr ? term.hist[((y) + term.histi - \
/* constants */ term.scr + HISTSIZE + 1) % HISTSIZE] : \
#define ISO14755CMD "dmenu -w \"$WINDOWID\" -p codepoint: </dev/null" term.line[(y) - term.scr])
enum term_mode { enum term_mode {
MODE_WRAP = 1 << 0, MODE_WRAP = 1 << 0,
@ -142,7 +142,7 @@ typedef struct {
/* ESC '[' [[ [<priv>] <arg> [;]] <mode> [<mode>]] */ /* ESC '[' [[ [<priv>] <arg> [;]] <mode> [<mode>]] */
typedef struct { typedef struct {
char buf[ESC_BUF_SIZ]; /* raw string */ char buf[ESC_BUF_SIZ]; /* raw string */
int len; /* raw string length */ size_t len; /* raw string length */
char priv; char priv;
int arg[ESC_ARG_SIZ]; int arg[ESC_ARG_SIZ];
int narg; /* nb of args */ int narg; /* nb of args */
@ -153,8 +153,9 @@ typedef struct {
/* ESC type [[ [<priv>] <arg> [;]] <mode>] ESC '\' */ /* ESC type [[ [<priv>] <arg> [;]] <mode>] ESC '\' */
typedef struct { typedef struct {
char type; /* ESC type ... */ char type; /* ESC type ... */
char buf[STR_BUF_SIZ]; /* raw string */ char *buf; /* allocated raw string */
int len; /* raw string length */ size_t siz; /* allocation size */
size_t len; /* raw string length */
char *args[STR_ARG_SIZ]; char *args[STR_ARG_SIZ];
int narg; /* nb of args */ int narg; /* nb of args */
} STREscape; } STREscape;
@ -217,7 +218,6 @@ static void selsnap(int *, int *, int);
static size_t utf8decode(const char *, Rune *, size_t); static size_t utf8decode(const char *, Rune *, size_t);
static Rune utf8decodebyte(char, size_t *); static Rune utf8decodebyte(char, size_t *);
static char utf8encodebyte(Rune, size_t); static char utf8encodebyte(Rune, size_t);
static char *utf8strchr(char *, Rune);
static size_t utf8validate(Rune *, size_t); static size_t utf8validate(Rune *, size_t);
static char *base64dec(const char *); static char *base64dec(const char *);
@ -259,10 +259,10 @@ xwrite(int fd, const char *s, size_t len)
void * void *
xmalloc(size_t len) xmalloc(size_t len)
{ {
void *p = malloc(len); void *p;
if (!p) if (!(p = malloc(len)))
die("Out of memory\n"); die("malloc: %s\n", strerror(errno));
return p; return p;
} }
@ -271,7 +271,7 @@ void *
xrealloc(void *p, size_t len) xrealloc(void *p, size_t len)
{ {
if ((p = realloc(p, len)) == NULL) if ((p = realloc(p, len)) == NULL)
die("Out of memory\n"); die("realloc: %s\n", strerror(errno));
return p; return p;
} }
@ -280,7 +280,7 @@ char *
xstrdup(char *s) xstrdup(char *s)
{ {
if ((s = strdup(s)) == NULL) if ((s = strdup(s)) == NULL)
die("Out of memory\n"); die("strdup: %s\n", strerror(errno));
return s; return s;
} }
@ -344,23 +344,6 @@ utf8encodebyte(Rune u, size_t i)
return utfbyte[i] | (u & ~utfmask[i]); return utfbyte[i] | (u & ~utfmask[i]);
} }
char *
utf8strchr(char *s, Rune u)
{
Rune r;
size_t i, j, len;
len = strlen(s);
for (i = 0, j = 0; i < len; i += j) {
if (!(j = utf8decode(&s[i], &r, len - i)))
break;
if (r == u)
return &(s[i]);
}
return NULL;
}
size_t size_t
utf8validate(Rune *u, size_t i) utf8validate(Rune *u, size_t i)
{ {
@ -391,7 +374,7 @@ char
base64dec_getc(const char **src) base64dec_getc(const char **src)
{ {
while (**src && !isprint(**src)) (*src)++; while (**src && !isprint(**src)) (*src)++;
return *((*src)++); return **src ? *((*src)++) : '='; /* emulate padding if string ends */
} }
char * char *
@ -409,6 +392,10 @@ base64dec(const char *src)
int c = base64_digits[(unsigned char) base64dec_getc(&src)]; int c = base64_digits[(unsigned char) base64dec_getc(&src)];
int d = base64_digits[(unsigned char) base64dec_getc(&src)]; int d = base64_digits[(unsigned char) base64dec_getc(&src)];
/* invalid input. 'a' can be -1, e.g. if src is "\n" (c-str) */
if (a == -1 || b == -1)
break;
*dst++ = (a << 2) | ((b & 0x30) >> 4); *dst++ = (a << 2) | ((b & 0x30) >> 4);
if (c == -1) if (c == -1)
break; break;
@ -449,6 +436,7 @@ selstart(int col, int row, int snap)
selclear(); selclear();
sel.mode = SEL_EMPTY; sel.mode = SEL_EMPTY;
sel.type = SEL_REGULAR; sel.type = SEL_REGULAR;
sel.alt = IS_SET(MODE_ALTSCREEN);
sel.snap = snap; sel.snap = snap;
sel.oe.x = sel.ob.x = col; sel.oe.x = sel.ob.x = col;
sel.oe.y = sel.ob.y = row; sel.oe.y = sel.ob.y = row;
@ -477,13 +465,12 @@ selextend(int col, int row, int type, int done)
oldsey = sel.ne.y; oldsey = sel.ne.y;
oldtype = sel.type; oldtype = sel.type;
sel.alt = IS_SET(MODE_ALTSCREEN);
sel.oe.x = col; sel.oe.x = col;
sel.oe.y = row; sel.oe.y = row;
selnormalize(); selnormalize();
sel.type = type; sel.type = type;
if (oldey != sel.oe.y || oldex != sel.oe.x || oldtype != sel.type) if (oldey != sel.oe.y || oldex != sel.oe.x || oldtype != sel.type || sel.mode == SEL_EMPTY)
tsetdirt(MIN(sel.nb.y, oldsby), MAX(sel.ne.y, oldsey)); tsetdirt(MIN(sel.nb.y, oldsby), MAX(sel.ne.y, oldsey));
sel.mode = done ? SEL_IDLE : SEL_READY; sel.mode = done ? SEL_IDLE : SEL_READY;
@ -733,13 +720,15 @@ sigchld(int a)
pid_t p; pid_t p;
if ((p = waitpid(pid, &stat, WNOHANG)) < 0) if ((p = waitpid(pid, &stat, WNOHANG)) < 0)
die("Waiting for pid %hd failed: %s\n", pid, strerror(errno)); die("waiting for pid %hd failed: %s\n", pid, strerror(errno));
if (pid != p) if (pid != p)
return; return;
if (!WIFEXITED(stat) || WEXITSTATUS(stat)) if (WIFEXITED(stat) && WEXITSTATUS(stat))
die("child finished with error '%d'\n", stat); die("child exited with status %d\n", WEXITSTATUS(stat));
else if (WIFSIGNALED(stat))
die("child terminated due to signal %d\n", WTERMSIG(stat));
exit(0); exit(0);
} }
@ -784,7 +773,8 @@ ttynew(char *line, char *cmd, char *out, char **args)
if (line) { if (line) {
if ((cmdfd = open(line, O_RDWR)) < 0) if ((cmdfd = open(line, O_RDWR)) < 0)
die("open line failed: %s\n", strerror(errno)); die("open line '%s' failed: %s\n",
line, strerror(errno));
dup2(cmdfd, 0); dup2(cmdfd, 0);
stty(args); stty(args);
return cmdfd; return cmdfd;
@ -796,7 +786,7 @@ ttynew(char *line, char *cmd, char *out, char **args)
switch (pid = fork()) { switch (pid = fork()) {
case -1: case -1:
die("fork failed\n"); die("fork failed: %s\n", strerror(errno));
break; break;
case 0: case 0:
close(iofd); close(iofd);
@ -808,9 +798,17 @@ ttynew(char *line, char *cmd, char *out, char **args)
die("ioctl TIOCSCTTY failed: %s\n", strerror(errno)); die("ioctl TIOCSCTTY failed: %s\n", strerror(errno));
close(s); close(s);
close(m); close(m);
#ifdef __OpenBSD__
if (pledge("stdio getpw proc exec", NULL) == -1)
die("pledge\n");
#endif
execsh(cmd, args); execsh(cmd, args);
break; break;
default: default:
#ifdef __OpenBSD__
if (pledge("stdio rpath tty proc", NULL) == -1)
die("pledge\n");
#endif
close(s); close(s);
cmdfd = m; cmdfd = m;
signal(SIGCHLD, sigchld); signal(SIGCHLD, sigchld);
@ -829,7 +827,7 @@ ttyread(void)
/* append read bytes to unprocessed bytes */ /* append read bytes to unprocessed bytes */
if ((ret = read(cmdfd, buf+buflen, LEN(buf)-buflen)) < 0) if ((ret = read(cmdfd, buf+buflen, LEN(buf)-buflen)) < 0)
die("Couldn't read from shell: %s\n", strerror(errno)); die("couldn't read from shell: %s\n", strerror(errno));
buflen += ret; buflen += ret;
written = twrite(buf, buflen, 0); written = twrite(buf, buflen, 0);
@ -838,9 +836,6 @@ ttyread(void)
if (buflen > 0) if (buflen > 0)
memmove(buf, buf + written, buflen); memmove(buf, buf + written, buflen);
if (term.scr > 0 && term.scr < HISTSIZE-1)
term.scr++;
return ret; return ret;
} }
@ -1094,7 +1089,6 @@ kscrollup(const Arg* a)
} }
} }
void void
tscrolldown(int orig, int n, int copyhist) tscrolldown(int orig, int n, int copyhist)
{ {
@ -1119,6 +1113,7 @@ tscrolldown(int orig, int n, int copyhist)
term.line[i-n] = temp; term.line[i-n] = temp;
} }
if (term.scr == 0)
selscroll(orig, n); selscroll(orig, n);
} }
@ -1137,6 +1132,9 @@ tscrollup(int orig, int n, int copyhist)
term.line[orig] = temp; term.line[orig] = temp;
} }
if (term.scr > 0 && term.scr < HISTSIZE)
term.scr = MIN(term.scr + n, HISTSIZE-1);
tclearregion(0, orig, term.col-1, orig+n-1); tclearregion(0, orig, term.col-1, orig+n-1);
tsetdirt(orig+n, term.bot); tsetdirt(orig+n, term.bot);
@ -1146,6 +1144,7 @@ tscrollup(int orig, int n, int copyhist)
term.line[i+n] = temp; term.line[i+n] = temp;
} }
if (term.scr == 0)
selscroll(orig, -n); selscroll(orig, -n);
} }
@ -1504,7 +1503,8 @@ tsetattr(int *attr, int l)
} else { } else {
fprintf(stderr, fprintf(stderr,
"erresc(default): gfx attr %d unknown\n", "erresc(default): gfx attr %d unknown\n",
attr[i]), csidump(); attr[i]);
csidump();
} }
break; break;
} }
@ -1624,6 +1624,7 @@ tsetmode(int priv, int set, int *args, int narg)
case 1015: /* urxvt mangled mouse mode; incompatible case 1015: /* urxvt mangled mouse mode; incompatible
and can be mistaken for other control and can be mistaken for other control
codes. */ codes. */
break;
default: default:
fprintf(stderr, fprintf(stderr,
"erresc: unknown private set/reset mode %d\n", "erresc: unknown private set/reset mode %d\n",
@ -1865,7 +1866,7 @@ csihandle(void)
void void
csidump(void) csidump(void)
{ {
int i; size_t i;
uint c; uint c;
fprintf(stderr, "ESC["); fprintf(stderr, "ESC[");
@ -1895,7 +1896,7 @@ csireset(void)
void void
strhandle(void) strhandle(void)
{ {
char *p = NULL; char *p = NULL, *dec;
int j, narg, par; int j, narg, par;
term.esc &= ~(ESC_STR_END|ESC_STR); term.esc &= ~(ESC_STR_END|ESC_STR);
@ -1913,8 +1914,6 @@ strhandle(void)
return; return;
case 52: case 52:
if (narg > 2) { if (narg > 2) {
char *dec;
dec = base64dec(strescseq.args[2]); dec = base64dec(strescseq.args[2]);
if (dec) { if (dec) {
xsetsel(dec); xsetsel(dec);
@ -1932,7 +1931,10 @@ strhandle(void)
case 104: /* color reset, here p = NULL */ case 104: /* color reset, here p = NULL */
j = (narg > 1) ? atoi(strescseq.args[1]) : -1; j = (narg > 1) ? atoi(strescseq.args[1]) : -1;
if (xsetcolorname(j, p)) { if (xsetcolorname(j, p)) {
fprintf(stderr, "erresc: invalid color %s\n", 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 { } else {
/* /*
* TODO if defaultbg color is changed, borders * TODO if defaultbg color is changed, borders
@ -1982,7 +1984,7 @@ strparse(void)
void void
strdump(void) strdump(void)
{ {
int i; size_t i;
uint c; uint c;
fprintf(stderr, "ESC%c", strescseq.type); fprintf(stderr, "ESC%c", strescseq.type);
@ -2009,7 +2011,10 @@ strdump(void)
void void
strreset(void) strreset(void)
{ {
memset(&strescseq, 0, sizeof(strescseq)); strescseq = (STREscape){
.buf = xrealloc(strescseq.buf, STR_BUF_SIZ),
.siz = STR_BUF_SIZ,
};
} }
void void
@ -2029,28 +2034,6 @@ tprinter(char *s, size_t len)
} }
} }
void
iso14755(const Arg *arg)
{
FILE *p;
char *us, *e, codepoint[9], uc[UTF_SIZ];
unsigned long utf32;
if (!(p = popen(ISO14755CMD, "r")))
return;
us = fgets(codepoint, sizeof(codepoint), p);
pclose(p);
if (!us || *us == '\0' || *us == '-' || strlen(us) > 7)
return;
if ((utf32 = strtoul(us, &e, 16)) == ULONG_MAX ||
(*e != '\n' && *e != '\0'))
return;
ttywrite(uc, utf8encode(utf32, uc), 1);
}
void void
toggleprinter(const Arg *arg) toggleprinter(const Arg *arg)
{ {
@ -2335,7 +2318,7 @@ eschandle(uchar ascii)
case 'Z': /* DECID -- Identify Terminal */ case 'Z': /* DECID -- Identify Terminal */
ttywrite(vtiden, strlen(vtiden), 0); ttywrite(vtiden, strlen(vtiden), 0);
break; break;
case 'c': /* RIS -- Reset to inital state */ case 'c': /* RIS -- Reset to initial state */
treset(); treset();
resettitle(); resettitle();
xloadcols(); xloadcols();
@ -2406,7 +2389,6 @@ tputc(Rune u)
goto check_control_code; goto check_control_code;
} }
if (IS_SET(MODE_SIXEL)) { if (IS_SET(MODE_SIXEL)) {
/* TODO: implement sixel mode */ /* TODO: implement sixel mode */
return; return;
@ -2414,7 +2396,7 @@ tputc(Rune u)
if (term.esc&ESC_DCS && strescseq.len == 0 && u == 'q') if (term.esc&ESC_DCS && strescseq.len == 0 && u == 'q')
term.mode |= MODE_SIXEL; term.mode |= MODE_SIXEL;
if (strescseq.len+len >= sizeof(strescseq.buf)-1) { if (strescseq.len+len >= strescseq.siz) {
/* /*
* Here is a bug in terminals. If the user never sends * Here is a bug in terminals. If the user never sends
* some code to stop the str or esc command, then st * some code to stop the str or esc command, then st
@ -2428,7 +2410,10 @@ tputc(Rune u)
* term.esc = 0; * term.esc = 0;
* strhandle(); * strhandle();
*/ */
if (strescseq.siz > (SIZE_MAX - UTF_SIZ) / 2)
return; return;
strescseq.siz *= 2;
strescseq.buf = xrealloc(strescseq.buf, strescseq.siz);
} }
memmove(&strescseq.buf[strescseq.len], c, len); memmove(&strescseq.buf[strescseq.len], c, len);
@ -2591,7 +2576,7 @@ tresize(int col, int row)
} }
} }
/* resize each r w to new width, zero-pad if needed */ /* resize each row to new width, zero-pad if needed */
for (i = 0; i < minrow; i++) { for (i = 0; i < minrow; i++) {
term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph)); term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph));
term.alt[i] = xrealloc(term.alt[i], col * sizeof(Glyph)); term.alt[i] = xrealloc(term.alt[i], col * sizeof(Glyph));
@ -2669,12 +2654,12 @@ draw(void)
cx--; cx--;
drawregion(0, 0, term.col, term.row); drawregion(0, 0, term.col, term.row);
if (term.scr == 0) { if (term.scr == 0)
xdrawcursor(cx, term.c.y, term.line[term.c.y][cx], xdrawcursor(cx, term.c.y, term.line[term.c.y][cx],
term.ocx, term.ocy, term.line[term.ocy][term.ocx]); term.ocx, term.ocy, term.line[term.ocy][term.ocx]);
}
term.ocx = cx, term.ocy = term.c.y; term.ocx = cx, term.ocy = term.c.y;
xfinishdraw(); xfinishdraw();
xximspot(term.ocx, term.ocy);
} }
void void

@ -3,9 +3,6 @@
#include <stdint.h> #include <stdint.h>
#include <sys/types.h> #include <sys/types.h>
/* Arbitrary size */
#define HISTSIZE 2000
/* macros */ /* macros */
#define MIN(a, b) ((a) < (b) ? (a) : (b)) #define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) < (b) ? (b) : (a)) #define MAX(a, b) ((a) < (b) ? (b) : (a))
@ -22,8 +19,6 @@
#define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b)) #define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b))
#define IS_TRUECOL(x) (1 << 24 & (x)) #define IS_TRUECOL(x) (1 << 24 & (x))
#define TLINE(y) ((y) < term.scr ? term.hist[((y) + term.histi - term.scr \
+ HISTSIZE + 1) % HISTSIZE] : term.line[(y) - term.scr])
enum glyph_attribute { enum glyph_attribute {
ATTR_NULL = 0, ATTR_NULL = 0,
@ -79,13 +74,15 @@ typedef union {
uint ui; uint ui;
float f; float f;
const void *v; const void *v;
const char *s;
} Arg; } Arg;
void die(const char *, ...); void die(const char *, ...);
void redraw(void); void redraw(void);
void draw(void); void draw(void);
void iso14755(const Arg *); void kscrolldown(const Arg *);
void kscrollup(const Arg *);
void printscreen(const Arg *); void printscreen(const Arg *);
void printsel(const Arg *); void printsel(const Arg *);
void sendbreak(const Arg *); void sendbreak(const Arg *);
@ -116,18 +113,13 @@ void *xmalloc(size_t);
void *xrealloc(void *, size_t); void *xrealloc(void *, size_t);
char *xstrdup(char *); char *xstrdup(char *);
void kscrolldown(const Arg *);
void kscrollup(const Arg *);
/* config.h globals */ /* config.h globals */
extern char *utmp; extern char *utmp;
extern char *stty_args; extern char *stty_args;
extern char *vtiden; extern char *vtiden;
extern char *worddelimiters; extern wchar_t *worddelimiters;
extern int allowaltscreen; extern int allowaltscreen;
extern char *termname; extern char *termname;
extern int usealtcolors;
extern unsigned int tabspaces; extern unsigned int tabspaces;
extern unsigned int alpha;
extern unsigned int defaultfg; extern unsigned int defaultfg;
extern unsigned int defaultbg; extern unsigned int defaultbg;

@ -189,10 +189,10 @@ st| simpleterm,
rmxx=\E[29m, rmxx=\E[29m,
smxx=\E[9m, smxx=\E[9m,
# tmux extensions, see TERMINFO EXTENSIONS in tmux(1) # tmux extensions, see TERMINFO EXTENSIONS in tmux(1)
Se,
Ss,
Tc, Tc,
Ms=\E]52;%p1%s;%p2%s\007, Ms=\E]52;%p1%s;%p2%s\007,
Se=\E[2 q,
Ss=\E[%p1%d q,
st-256color| simpleterm with 256 colors, st-256color| simpleterm with 256 colors,
use=st, use=st,

@ -36,3 +36,4 @@ void xsetmode(int, unsigned int);
void xsetpointermotion(int); void xsetpointermotion(int);
void xsetsel(char *); void xsetsel(char *);
int xstartdraw(void); int xstartdraw(void);
void xximspot(int, int);

@ -29,9 +29,11 @@ typedef struct {
} Shortcut; } Shortcut;
typedef struct { typedef struct {
uint b; uint mod;
uint mask; uint button;
char *s; void (*func)(const Arg *);
const Arg arg;
uint release;
} MouseShortcut; } MouseShortcut;
typedef struct { typedef struct {
@ -48,19 +50,15 @@ typedef struct {
#define XK_NO_MOD 0 #define XK_NO_MOD 0
#define XK_SWITCH_MOD (1<<13) #define XK_SWITCH_MOD (1<<13)
/* alpha */
#define OPAQUE 0Xff
#define USE_ARGB (alpha != OPAQUE && opt_embed == NULL)
/* function definitions used in config.h */ /* function definitions used in config.h */
static void clipcopy(const Arg *); static void clipcopy(const Arg *);
static void clippaste(const Arg *); static void clippaste(const Arg *);
static void numlock(const Arg *); static void numlock(const Arg *);
static void selpaste(const Arg *); static void selpaste(const Arg *);
static void swapcolors(const Arg *);
static void zoom(const Arg *); static void zoom(const Arg *);
static void zoomabs(const Arg *); static void zoomabs(const Arg *);
static void zoomreset(const Arg *); static void zoomreset(const Arg *);
static void ttysend(const Arg *);
/* config.h for applying patches and the configuration. */ /* config.h for applying patches and the configuration. */
#include "config.h" #include "config.h"
@ -96,19 +94,17 @@ typedef struct {
Drawable buf; Drawable buf;
GlyphFontSpec *specbuf; /* font spec buffer used for rendering */ GlyphFontSpec *specbuf; /* font spec buffer used for rendering */
Atom xembed, wmdeletewin, netwmname, netwmpid; Atom xembed, wmdeletewin, netwmname, netwmpid;
struct {
XIM xim; XIM xim;
XIC xic; XIC xic;
XPoint spot;
XVaNestedList spotlist;
} ime;
Draw draw; Draw draw;
Visual *vis; Visual *vis;
XSetWindowAttributes attrs; 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 scr;
int isfixed; /* is fixed geometry? */ int isfixed; /* is fixed geometry? */
int depth; /* bit depth */
int l, t; /* left and top offset */ int l, t; /* left and top offset */
int gm; /* geometry mask */ int gm; /* geometry mask */
} XWindow; } XWindow;
@ -150,6 +146,10 @@ static void xdrawglyphfontspecs(const XftGlyphFontSpec *, Glyph, int, int, int);
static void xdrawglyph(Glyph, int, int); static void xdrawglyph(Glyph, int, int);
static void xclear(int, int, int, int); static void xclear(int, int, int, int);
static int xgeommasktogravity(int); static int xgeommasktogravity(int);
static int ximopen(Display *);
static void ximinstantiate(Display *, XPointer, XPointer);
static void ximdestroy(XIM, XPointer, XPointer);
static int xicdestroy(XIC, XPointer, XPointer);
static void xinit(int, int); static void xinit(int, int);
static void cresize(int, int); static void cresize(int, int);
static void xresize(int, int); static void xresize(int, int);
@ -171,6 +171,8 @@ static void kpress(XEvent *);
static void cmessage(XEvent *); static void cmessage(XEvent *);
static void resize(XEvent *); static void resize(XEvent *);
static void focus(XEvent *); static void focus(XEvent *);
static uint buttonmask(uint);
static int mouseaction(XEvent *, uint);
static void brelease(XEvent *); static void brelease(XEvent *);
static void bpress(XEvent *); static void bpress(XEvent *);
static void bmotion(XEvent *); static void bmotion(XEvent *);
@ -234,8 +236,9 @@ typedef struct {
} Fontcache; } Fontcache;
/* Fontcache is an array now. A new font will be appended to the array. */ /* Fontcache is an array now. A new font will be appended to the array. */
static Fontcache frc[16]; static Fontcache *frc = NULL;
static int frclen = 0; static int frclen = 0;
static int frccap = 0;
static char *usedfont = NULL; static char *usedfont = NULL;
static double usedfontsize = 0; static double usedfontsize = 0;
static double defaultfontsize = 0; static double defaultfontsize = 0;
@ -251,21 +254,6 @@ static char *opt_title = NULL;
static int oldbutton = 3; /* button event on startup: 3 = release */ static int oldbutton = 3; /* button event on startup: 3 = release */
int usealtcolors = 0; /* 1 to use alternate palette */
void
swapcolors(const Arg *dummy)
{
usealtcolors = !usealtcolors;
xloadcols();
redraw();
}
const char* getcolorname(int i)
{
return (usealtcolors) ? altcolorname[i] : colorname[i];
}
void void
clipcopy(const Arg *dummy) clipcopy(const Arg *dummy)
{ {
@ -334,6 +322,12 @@ zoomreset(const Arg *arg)
} }
} }
void
ttysend(const Arg *arg)
{
ttywrite(arg->s, strlen(arg->s), 1);
}
int int
evcol(XEvent *e) evcol(XEvent *e)
{ {
@ -354,7 +348,7 @@ void
mousesel(XEvent *e, int done) mousesel(XEvent *e, int done)
{ {
int type, seltype = SEL_REGULAR; int type, seltype = SEL_REGULAR;
uint state = e->xbutton.state & ~(Button1Mask | forceselmod); uint state = e->xbutton.state & ~(Button1Mask | forcemousemod);
for (type = 1; type < LEN(selmasks); ++type) { for (type = 1; type < LEN(selmasks); ++type) {
if (match(selmasks[type], state)) { if (match(selmasks[type], state)) {
@ -430,25 +424,51 @@ mousereport(XEvent *e)
ttywrite(buf, len, 0); ttywrite(buf, len, 0);
} }
uint
buttonmask(uint button)
{
return button == Button1 ? Button1Mask
: button == Button2 ? Button2Mask
: button == Button3 ? Button3Mask
: button == Button4 ? Button4Mask
: button == Button5 ? Button5Mask
: 0;
}
int
mouseaction(XEvent *e, uint release)
{
MouseShortcut *ms;
/* ignore Button<N>mask for Button<N> - 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 &&
(match(ms->mod, state) || /* exact or forced */
match(ms->mod, state & ~forcemousemod))) {
ms->func(&(ms->arg));
return 1;
}
}
return 0;
}
void void
bpress(XEvent *e) bpress(XEvent *e)
{ {
struct timespec now; struct timespec now;
MouseShortcut *ms;
int snap; int snap;
if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) { if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) {
mousereport(e); mousereport(e);
return; return;
} }
for (ms = mshortcuts; ms < mshortcuts + LEN(mshortcuts); ms++) { if (mouseaction(e, 0))
if (e->xbutton.button == ms->b
&& match(ms->mask, e->xbutton.state)) {
ttywrite(ms->s, strlen(ms->s), 1);
return; return;
}
}
if (e->xbutton.button == Button1) { if (e->xbutton.button == Button1) {
/* /*
@ -653,8 +673,6 @@ setsel(char *str, Time t)
XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t); XSetSelectionOwner(xw.dpy, XA_PRIMARY, xw.win, t);
if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win) if (XGetSelectionOwner(xw.dpy, XA_PRIMARY) != xw.win)
selclear(); selclear();
clipcopy(NULL);
} }
void void
@ -666,28 +684,21 @@ xsetsel(char *str)
void void
brelease(XEvent *e) brelease(XEvent *e)
{ {
if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forceselmod)) { if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) {
mousereport(e); mousereport(e);
return; return;
} }
if (e->xbutton.button == Button2) if (mouseaction(e, 1))
selpaste(NULL); return;
else if (e->xbutton.button == Button1) if (e->xbutton.button == Button1)
mousesel(e, 1); mousesel(e, 1);
} }
void void
bmotion(XEvent *e) bmotion(XEvent *e)
{ {
if (!xw.pointerisvisible) { if (IS_SET(MODE_MOUSE) && !(e->xbutton.state & forcemousemod)) {
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 & forceselmod)) {
mousereport(e); mousereport(e);
return; return;
} }
@ -707,6 +718,8 @@ cresize(int width, int height)
col = (win.w - 2 * borderpx) / win.cw; col = (win.w - 2 * borderpx) / win.cw;
row = (win.h - 2 * borderpx) / win.ch; row = (win.h - 2 * borderpx) / win.ch;
col = MAX(1, col);
row = MAX(1, row);
tresize(col, row); tresize(col, row);
xresize(col, row); xresize(col, row);
@ -716,12 +729,12 @@ cresize(int width, int height)
void void
xresize(int col, int row) xresize(int col, int row)
{ {
win.tw = MAX(1, col * win.cw); win.tw = col * win.cw;
win.th = MAX(1, row * win.ch); win.th = row * win.ch;
XFreePixmap(xw.dpy, xw.buf); XFreePixmap(xw.dpy, xw.buf);
xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h,
xw.depth); DefaultDepth(xw.dpy, xw.scr));
XftDrawChange(xw.draw, xw.buf); XftDrawChange(xw.draw, xw.buf);
xclear(0, 0, win.w, win.h); xclear(0, 0, win.w, win.h);
@ -753,7 +766,7 @@ xloadcolor(int i, const char *name, Color *ncolor)
return XftColorAllocValue(xw.dpy, xw.vis, return XftColorAllocValue(xw.dpy, xw.vis,
xw.cmap, &color, ncolor); xw.cmap, &color, ncolor);
} else } else
name = getcolorname(i); name = colorname[i];
} }
return XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, ncolor); return XftColorAllocName(xw.dpy, xw.vis, xw.cmap, name, ncolor);
@ -766,28 +779,20 @@ xloadcols(void)
static int loaded; static int loaded;
Color *cp; Color *cp;
dc.collen = MAX(LEN(colorname), LEN(altcolorname));
dc.col = xmalloc(dc.collen * sizeof(Color));
if (loaded) { if (loaded) {
for (cp = dc.col; cp < &dc.col[dc.collen]; ++cp) for (cp = dc.col; cp < &dc.col[dc.collen]; ++cp)
XftColorFree(xw.dpy, xw.vis, xw.cmap, 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++) for (i = 0; i < dc.collen; i++)
if (!xloadcolor(i, NULL, &dc.col[i])) { if (!xloadcolor(i, NULL, &dc.col[i])) {
if (getcolorname(i)) if (colorname[i])
die("Could not allocate color '%s'\n", getcolorname(i)); die("could not allocate color '%s'\n", colorname[i]);
else else
die("Could not allocate color %d\n", i); die("could not allocate color %d\n", i);
}
/* set alpha value of bg color */
if (USE_ARGB) {
dc.col[defaultbg].color.alpha = alpha << 8;
dc.col[defaultbg].color.red = ((dc.col[defaultbg].color.red >> 8) * alpha / 255) << 8;
dc.col[defaultbg].color.green = ((dc.col[defaultbg].color.green >> 8) * alpha / 255) << 8;
dc.col[defaultbg].color.blue = ((dc.col[defaultbg].color.blue >> 8) * alpha / 255) << 8;
} }
loaded = 1; loaded = 1;
} }
@ -800,7 +805,6 @@ xsetcolorname(int x, const char *name)
if (!BETWEEN(x, 0, dc.collen)) if (!BETWEEN(x, 0, dc.collen))
return 1; return 1;
if (!xloadcolor(x, name, &ncolor)) if (!xloadcolor(x, name, &ncolor))
return 1; return 1;
@ -810,17 +814,6 @@ xsetcolorname(int x, const char *name)
return 0; return 0;
} }
void
xtermclear(int col1, int row1, int col2, int row2)
{
XftDrawRect(xw.draw,
&dc.col[IS_SET(MODE_REVERSE) ? defaultfg : defaultbg],
borderpx + col1 * win.cw,
borderpx + row1 * win.ch,
(col2-col1+1) * win.cw,
(row2-row1+1) * win.ch);
}
/* /*
* Absolute coordinates. * Absolute coordinates.
*/ */
@ -842,15 +835,17 @@ xhints(void)
sizeh = XAllocSizeHints(); sizeh = XAllocSizeHints();
sizeh->flags = PSize | PResizeInc | PBaseSize; sizeh->flags = PSize | PResizeInc | PBaseSize | PMinSize;
sizeh->height = win.h; sizeh->height = win.h;
sizeh->width = win.w; sizeh->width = win.w;
sizeh->height_inc = win.ch; sizeh->height_inc = win.ch;
sizeh->width_inc = win.cw; sizeh->width_inc = win.cw;
sizeh->base_height = 2 * borderpx; sizeh->base_height = 2 * borderpx;
sizeh->base_width = 2 * borderpx; sizeh->base_width = 2 * borderpx;
sizeh->min_height = win.ch + 2 * borderpx;
sizeh->min_width = win.cw + 2 * borderpx;
if (xw.isfixed) { if (xw.isfixed) {
sizeh->flags |= PMaxSize | PMinSize; sizeh->flags |= PMaxSize;
sizeh->min_width = sizeh->max_width = win.w; sizeh->min_width = sizeh->max_width = win.w;
sizeh->min_height = sizeh->max_height = win.h; sizeh->min_height = sizeh->max_height = win.h;
} }
@ -923,7 +918,7 @@ xloadfont(Font *f, FcPattern *pattern)
if ((XftPatternGetInteger(f->match->pattern, "slant", 0, if ((XftPatternGetInteger(f->match->pattern, "slant", 0,
&haveattr) != XftResultMatch) || haveattr < wantattr) { &haveattr) != XftResultMatch) || haveattr < wantattr) {
f->badslant = 1; f->badslant = 1;
fputs("st: font slant does not match\n", stderr); fputs("font slant does not match\n", stderr);
} }
} }
@ -932,7 +927,7 @@ xloadfont(Font *f, FcPattern *pattern)
if ((XftPatternGetInteger(f->match->pattern, "weight", 0, if ((XftPatternGetInteger(f->match->pattern, "weight", 0,
&haveattr) != XftResultMatch) || haveattr != wantattr) { &haveattr) != XftResultMatch) || haveattr != wantattr) {
f->badweight = 1; f->badweight = 1;
fputs("st: font weight does not match\n", stderr); fputs("font weight does not match\n", stderr);
} }
} }
@ -960,14 +955,13 @@ xloadfonts(char *fontstr, double fontsize)
FcPattern *pattern; FcPattern *pattern;
double fontval; double fontval;
if (fontstr[0] == '-') { if (fontstr[0] == '-')
pattern = XftXlfdParse(fontstr, False, False); pattern = XftXlfdParse(fontstr, False, False);
} else { else
pattern = FcNameParse((FcChar8 *)fontstr); pattern = FcNameParse((FcChar8 *)fontstr);
}
if (!pattern) if (!pattern)
die("st: can't open font %s\n", fontstr); die("can't open font %s\n", fontstr);
if (fontsize > 1) { if (fontsize > 1) {
FcPatternDel(pattern, FC_PIXEL_SIZE); FcPatternDel(pattern, FC_PIXEL_SIZE);
@ -993,7 +987,7 @@ xloadfonts(char *fontstr, double fontsize)
} }
if (xloadfont(&dc.font, pattern)) if (xloadfont(&dc.font, pattern))
die("st: can't open font %s\n", fontstr); die("can't open font %s\n", fontstr);
if (usedfontsize < 0) { if (usedfontsize < 0) {
FcPatternGetDouble(dc.font.match->pattern, FcPatternGetDouble(dc.font.match->pattern,
@ -1010,17 +1004,17 @@ xloadfonts(char *fontstr, double fontsize)
FcPatternDel(pattern, FC_SLANT); FcPatternDel(pattern, FC_SLANT);
FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC); FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ITALIC);
if (xloadfont(&dc.ifont, pattern)) if (xloadfont(&dc.ifont, pattern))
die("st: can't open font %s\n", fontstr); die("can't open font %s\n", fontstr);
FcPatternDel(pattern, FC_WEIGHT); FcPatternDel(pattern, FC_WEIGHT);
FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD); FcPatternAddInteger(pattern, FC_WEIGHT, FC_WEIGHT_BOLD);
if (xloadfont(&dc.ibfont, pattern)) if (xloadfont(&dc.ibfont, pattern))
die("st: can't open font %s\n", fontstr); die("can't open font %s\n", fontstr);
FcPatternDel(pattern, FC_SLANT); FcPatternDel(pattern, FC_SLANT);
FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN); FcPatternAddInteger(pattern, FC_SLANT, FC_SLANT_ROMAN);
if (xloadfont(&dc.bfont, pattern)) if (xloadfont(&dc.bfont, pattern))
die("st: can't open font %s\n", fontstr); die("can't open font %s\n", fontstr);
FcPatternDestroy(pattern); FcPatternDestroy(pattern);
} }
@ -1047,66 +1041,83 @@ xunloadfonts(void)
xunloadfont(&dc.ibfont); xunloadfont(&dc.ibfont);
} }
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;
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);
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;
}
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);
}
int
xicdestroy(XIC xim, XPointer client, XPointer call)
{
xw.ime.xic = NULL;
return 1;
}
void void
xinit(int cols, int rows) xinit(int cols, int rows)
{ {
XGCValues gcvalues; XGCValues gcvalues;
Cursor cursor;
Window parent; Window parent;
pid_t thispid = getpid(); pid_t thispid = getpid();
XColor xmousefg, xmousebg; XColor xmousefg, xmousebg;
Pixmap blankpm;
if (!(xw.dpy = XOpenDisplay(NULL))) if (!(xw.dpy = XOpenDisplay(NULL)))
die("Can't open display\n"); die("can't open display\n");
xw.scr = XDefaultScreen(xw.dpy); xw.scr = XDefaultScreen(xw.dpy);
xw.depth = (USE_ARGB) ? 32: XDefaultDepth(xw.dpy, xw.scr);
if (!USE_ARGB)
xw.vis = XDefaultVisual(xw.dpy, xw.scr); xw.vis = XDefaultVisual(xw.dpy, xw.scr);
else {
XVisualInfo *vis;
XRenderPictFormat *fmt;
int nvi;
int i;
XVisualInfo tpl = {
.screen = xw.scr,
.depth = 32,
.class = TrueColor
};
vis = XGetVisualInfo(xw.dpy,
VisualScreenMask | VisualDepthMask | VisualClassMask,
&tpl, &nvi);
xw.vis = NULL;
for (i = 0; i < nvi; i++) {
fmt = XRenderFindVisualFormat(xw.dpy, vis[i].visual);
if (fmt->type == PictTypeDirect && fmt->direct.alphaMask) {
xw.vis = vis[i].visual;
break;
}
}
XFree(vis);
if (!xw.vis) {
fprintf(stderr, "Couldn't find ARGB visual.\n");
exit(1);
}
}
/* font */ /* font */
if (!FcInit()) if (!FcInit())
die("Could not init fontconfig.\n"); die("could not init fontconfig.\n");
usedfont = (opt_font == NULL)? font : opt_font; usedfont = (opt_font == NULL)? font : opt_font;
xloadfonts(usedfont, 0); xloadfonts(usedfont, 0);
/* colors */ /* colors */
if (!USE_ARGB)
xw.cmap = XDefaultColormap(xw.dpy, xw.scr); xw.cmap = XDefaultColormap(xw.dpy, xw.scr);
else
xw.cmap = XCreateColormap(xw.dpy, XRootWindow(xw.dpy, xw.scr),
xw.vis, None);
xloadcols(); xloadcols();
/* adjust fixed window geometry */ /* adjust fixed window geometry */
@ -1121,7 +1132,7 @@ xinit(int cols, int rows)
xw.attrs.background_pixel = dc.col[defaultbg].pixel; xw.attrs.background_pixel = dc.col[defaultbg].pixel;
xw.attrs.border_pixel = dc.col[defaultbg].pixel; xw.attrs.border_pixel = dc.col[defaultbg].pixel;
xw.attrs.bit_gravity = NorthWestGravity; xw.attrs.bit_gravity = NorthWestGravity;
xw.attrs.event_mask = FocusChangeMask | KeyPressMask xw.attrs.event_mask = FocusChangeMask | KeyPressMask | KeyReleaseMask
| ExposureMask | VisibilityChangeMask | StructureNotifyMask | ExposureMask | VisibilityChangeMask | StructureNotifyMask
| ButtonMotionMask | ButtonPressMask | ButtonReleaseMask; | ButtonMotionMask | ButtonPressMask | ButtonReleaseMask;
xw.attrs.colormap = xw.cmap; xw.attrs.colormap = xw.cmap;
@ -1129,15 +1140,16 @@ xinit(int cols, int rows)
if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0)))) if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0))))
parent = XRootWindow(xw.dpy, xw.scr); parent = XRootWindow(xw.dpy, xw.scr);
xw.win = XCreateWindow(xw.dpy, parent, xw.l, xw.t, xw.win = XCreateWindow(xw.dpy, parent, xw.l, xw.t,
win.w, win.h, 0, xw.depth, InputOutput, win.w, win.h, 0, XDefaultDepth(xw.dpy, xw.scr), InputOutput,
xw.vis, CWBackPixel | CWBorderPixel | CWBitGravity xw.vis, CWBackPixel | CWBorderPixel | CWBitGravity
| CWEventMask | CWColormap, &xw.attrs); | CWEventMask | CWColormap, &xw.attrs);
memset(&gcvalues, 0, sizeof(gcvalues)); memset(&gcvalues, 0, sizeof(gcvalues));
gcvalues.graphics_exposures = False; gcvalues.graphics_exposures = False;
xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h, xw.depth); dc.gc = XCreateGC(xw.dpy, parent, GCGraphicsExposures,
dc.gc = XCreateGC(xw.dpy, (USE_ARGB) ? xw.buf: parent, &gcvalues);
GCGraphicsExposures, &gcvalues); xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h,
DefaultDepth(xw.dpy, xw.scr));
XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel); XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel);
XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h); XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h);
@ -1148,44 +1160,28 @@ xinit(int cols, int rows)
xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap); xw.draw = XftDrawCreate(xw.dpy, xw.buf, xw.vis, xw.cmap);
/* input methods */ /* input methods */
if ((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) { if (!ximopen(xw.dpy)) {
XSetLocaleModifiers("@im=local"); XRegisterIMInstantiateCallback(xw.dpy, NULL, NULL, NULL,
if ((xw.xim = XOpenIM(xw.dpy, NULL, NULL, NULL)) == NULL) { ximinstantiate, NULL);
XSetLocaleModifiers("@im=");
if ((xw.xim = XOpenIM(xw.dpy,
NULL, NULL, NULL)) == NULL) {
die("XOpenIM failed. Could not open input"
" device.\n");
}
}
} }
xw.xic = XCreateIC(xw.xim, XNInputStyle, XIMPreeditNothing
| XIMStatusNothing, XNClientWindow, xw.win,
XNFocusWindow, xw.win, NULL);
if (xw.xic == NULL)
die("XCreateIC failed. Could not obtain input method.\n");
/* white cursor, black outline */ /* white cursor, black outline */
xw.pointerisvisible = 1; cursor = XCreateFontCursor(xw.dpy, mouseshape);
xw.vpointer = XCreateFontCursor(xw.dpy, mouseshape); XDefineCursor(xw.dpy, xw.win, cursor);
XDefineCursor(xw.dpy, xw.win, xw.vpointer);
if (XParseColor(xw.dpy, xw.cmap, getcolorname(mousefg), &xmousefg) == 0) { if (XParseColor(xw.dpy, xw.cmap, colorname[mousefg], &xmousefg) == 0) {
xmousefg.red = 0xffff; xmousefg.red = 0xffff;
xmousefg.green = 0xffff; xmousefg.green = 0xffff;
xmousefg.blue = 0xffff; xmousefg.blue = 0xffff;
} }
if (XParseColor(xw.dpy, xw.cmap, getcolorname(mousefg), &xmousebg) == 0) { if (XParseColor(xw.dpy, xw.cmap, colorname[mousebg], &xmousebg) == 0) {
xmousebg.red = 0x0000; xmousebg.red = 0x0000;
xmousebg.green = 0x0000; xmousebg.green = 0x0000;
xmousebg.blue = 0x0000; xmousebg.blue = 0x0000;
} }
XRecolorCursor(xw.dpy, xw.vpointer, &xmousefg, &xmousebg); XRecolorCursor(xw.dpy, cursor, &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.xembed = XInternAtom(xw.dpy, "_XEMBED", False);
xw.wmdeletewin = XInternAtom(xw.dpy, "WM_DELETE_WINDOW", False); xw.wmdeletewin = XInternAtom(xw.dpy, "WM_DELETE_WINDOW", False);
@ -1198,8 +1194,8 @@ xinit(int cols, int rows)
win.mode = MODE_NUMLOCK; win.mode = MODE_NUMLOCK;
resettitle(); resettitle();
XMapWindow(xw.dpy, xw.win);
xhints(); xhints();
XMapWindow(xw.dpy, xw.win);
XSync(xw.dpy, False); XSync(xw.dpy, False);
clock_gettime(CLOCK_MONOTONIC, &xsel.tclick1); clock_gettime(CLOCK_MONOTONIC, &xsel.tclick1);
@ -1309,13 +1305,10 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
fontpattern = FcFontSetMatch(0, fcsets, 1, fontpattern = FcFontSetMatch(0, fcsets, 1,
fcpattern, &fcres); fcpattern, &fcres);
/* /* Allocate memory for the new cache entry. */
* Overwrite or create the new cache entry. if (frclen >= frccap) {
*/ frccap += 16;
if (frclen >= LEN(frc)) { frc = xrealloc(frc, frccap * sizeof(Fontcache));
frclen = LEN(frc) - 1;
XftFontClose(xw.dpy, frc[frclen].font);
frc[frclen].unicodep = 0;
} }
frc[frclen].font = XftFontOpenPattern(xw.dpy, frc[frclen].font = XftFontOpenPattern(xw.dpy,
@ -1389,7 +1382,7 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
/* Change basic system colors [0-7] to bright system colors [8-15] */ /* 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)) if ((base.mode & ATTR_BOLD_FAINT) == ATTR_BOLD && BETWEEN(base.fg, 0, 7))
fg = &dc.col[base.fg]; fg = &dc.col[base.fg + 8];
if (IS_SET(MODE_REVERSE)) { if (IS_SET(MODE_REVERSE)) {
if (fg == &dc.col[defaultfg]) { if (fg == &dc.col[defaultfg]) {
@ -1645,6 +1638,18 @@ xfinishdraw(void)
defaultfg : defaultbg].pixel); defaultfg : defaultbg].pixel);
} }
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;
XSetICValues(xw.ime.xic, XNPreeditAttributes, xw.ime.spotlist, NULL);
}
void void
expose(XEvent *ev) expose(XEvent *ev)
{ {
@ -1668,8 +1673,6 @@ unmap(XEvent *ev)
void void
xsetpointermotion(int set) xsetpointermotion(int set)
{ {
if (!set && !xw.pointerisvisible)
return;
MODBIT(xw.attrs.event_mask, set, PointerMotionMask); MODBIT(xw.attrs.event_mask, set, PointerMotionMask);
XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, &xw.attrs); XChangeWindowAttributes(xw.dpy, xw.win, CWEventMask, &xw.attrs);
} }
@ -1721,13 +1724,15 @@ focus(XEvent *ev)
return; return;
if (ev->type == FocusIn) { if (ev->type == FocusIn) {
XSetICFocus(xw.xic); if (xw.ime.xic)
XSetICFocus(xw.ime.xic);
win.mode |= MODE_FOCUSED; win.mode |= MODE_FOCUSED;
xseturgency(0); xseturgency(0);
if (IS_SET(MODE_FOCUS)) if (IS_SET(MODE_FOCUS))
ttywrite("\033[I", 3, 0); ttywrite("\033[I", 3, 0);
} else { } else {
XUnsetICFocus(xw.xic); if (xw.ime.xic)
XUnsetICFocus(xw.ime.xic);
win.mode &= ~MODE_FOCUSED; win.mode &= ~MODE_FOCUSED;
if (IS_SET(MODE_FOCUS)) if (IS_SET(MODE_FOCUS))
ttywrite("\033[O", 3, 0); ttywrite("\033[O", 3, 0);
@ -1782,22 +1787,19 @@ kpress(XEvent *ev)
{ {
XKeyEvent *e = &ev->xkey; XKeyEvent *e = &ev->xkey;
KeySym ksym; KeySym ksym;
char buf[32], *customkey; char buf[64], *customkey;
int len; int len;
Rune c; Rune c;
Status status; Status status;
Shortcut *bp; Shortcut *bp;
if (xw.pointerisvisible) {
XDefineCursor(xw.dpy, xw.win, xw.bpointer);
xsetpointermotion(1);
xw.pointerisvisible = 0;
}
if (IS_SET(MODE_KBDLOCK)) if (IS_SET(MODE_KBDLOCK))
return; return;
len = XmbLookupString(xw.xic, e, buf, sizeof buf, &ksym, &status); if (xw.ime.xic)
len = XmbLookupString(xw.ime.xic, e, buf, sizeof buf, &ksym, &status);
else
len = XLookupString(e, buf, sizeof buf, &ksym, NULL);
/* 1. shortcuts */ /* 1. shortcuts */
for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) { for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) {
if (ksym == bp->keysym && match(bp->mod, e->state)) { if (ksym == bp->keysym && match(bp->mod, e->state)) {
@ -1830,7 +1832,6 @@ kpress(XEvent *ev)
ttywrite(buf, len, 1); ttywrite(buf, len, 1);
} }
void void
cmessage(XEvent *e) cmessage(XEvent *e)
{ {
@ -2027,7 +2028,7 @@ main(int argc, char *argv[])
opt_embed = EARGF(usage()); opt_embed = EARGF(usage());
break; break;
case 'v': case 'v':
die("%s " VERSION " (c) 2010-2016 st engineers\n", argv0); die("%s " VERSION "\n", argv0);
break; break;
default: default:
usage(); usage();

Loading…
Cancel
Save