All my suckless software
This commit is contained in:
@@ -0,0 +1,4 @@
|
|||||||
|
*.o
|
||||||
|
dmenu
|
||||||
|
stest
|
||||||
|
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
MIT/X Consortium License
|
||||||
|
|
||||||
|
© 2006-2019 Anselm R Garbe <anselm@garbe.ca>
|
||||||
|
© 2006-2008 Sander van Dijk <a.h.vandijk@gmail.com>
|
||||||
|
© 2006-2007 Michał Janeczek <janeczek@gmail.com>
|
||||||
|
© 2007 Kris Maglione <jg@suckless.org>
|
||||||
|
© 2009 Gottox <gottox@s01.de>
|
||||||
|
© 2009 Markus Schnalke <meillo@marmaro.de>
|
||||||
|
© 2009 Evan Gates <evan.gates@gmail.com>
|
||||||
|
© 2010-2012 Connor Lane Smith <cls@lubutu.com>
|
||||||
|
© 2014-2020 Hiltjo Posthuma <hiltjo@codemadness.org>
|
||||||
|
© 2015-2019 Quentin Rameau <quinq@fifth.space>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
copy of this software and associated documentation files (the "Software"),
|
||||||
|
to deal in the Software without restriction, including without limitation
|
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
# dmenu - dynamic menu
|
||||||
|
# See LICENSE file for copyright and license details.
|
||||||
|
|
||||||
|
include config.mk
|
||||||
|
|
||||||
|
SRC = drw.c dmenu.c stest.c util.c
|
||||||
|
OBJ = $(SRC:.c=.o)
|
||||||
|
|
||||||
|
all: options dmenu stest
|
||||||
|
|
||||||
|
options:
|
||||||
|
@echo dmenu build options:
|
||||||
|
@echo "CFLAGS = $(CFLAGS)"
|
||||||
|
@echo "LDFLAGS = $(LDFLAGS)"
|
||||||
|
@echo "CC = $(CC)"
|
||||||
|
|
||||||
|
.c.o:
|
||||||
|
$(CC) -c $(CFLAGS) $<
|
||||||
|
|
||||||
|
config.h:
|
||||||
|
cp config.def.h $@
|
||||||
|
|
||||||
|
$(OBJ): arg.h config.h config.mk drw.h
|
||||||
|
|
||||||
|
dmenu: dmenu.o drw.o util.o
|
||||||
|
$(CC) -o $@ dmenu.o drw.o util.o $(LDFLAGS)
|
||||||
|
|
||||||
|
stest: stest.o
|
||||||
|
$(CC) -o $@ stest.o $(LDFLAGS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f dmenu stest $(OBJ) dmenu-$(VERSION).tar.gz
|
||||||
|
|
||||||
|
dist: clean
|
||||||
|
mkdir -p dmenu-$(VERSION)
|
||||||
|
cp LICENSE Makefile README arg.h config.def.h config.mk dmenu.1\
|
||||||
|
drw.h util.h dmenu_path dmenu_run stest.1 $(SRC)\
|
||||||
|
dmenu-$(VERSION)
|
||||||
|
tar -cf dmenu-$(VERSION).tar dmenu-$(VERSION)
|
||||||
|
gzip dmenu-$(VERSION).tar
|
||||||
|
rm -rf dmenu-$(VERSION)
|
||||||
|
|
||||||
|
install: all
|
||||||
|
mkdir -p $(DESTDIR)$(PREFIX)/bin
|
||||||
|
cp -f dmenu dmenu_path dmenu_run stest $(DESTDIR)$(PREFIX)/bin
|
||||||
|
chmod 755 $(DESTDIR)$(PREFIX)/bin/dmenu
|
||||||
|
chmod 755 $(DESTDIR)$(PREFIX)/bin/dmenu_path
|
||||||
|
chmod 755 $(DESTDIR)$(PREFIX)/bin/dmenu_run
|
||||||
|
chmod 755 $(DESTDIR)$(PREFIX)/bin/stest
|
||||||
|
mkdir -p $(DESTDIR)$(MANPREFIX)/man1
|
||||||
|
sed "s/VERSION/$(VERSION)/g" < dmenu.1 > $(DESTDIR)$(MANPREFIX)/man1/dmenu.1
|
||||||
|
sed "s/VERSION/$(VERSION)/g" < stest.1 > $(DESTDIR)$(MANPREFIX)/man1/stest.1
|
||||||
|
chmod 644 $(DESTDIR)$(MANPREFIX)/man1/dmenu.1
|
||||||
|
chmod 644 $(DESTDIR)$(MANPREFIX)/man1/stest.1
|
||||||
|
|
||||||
|
uninstall:
|
||||||
|
rm -f $(DESTDIR)$(PREFIX)/bin/dmenu\
|
||||||
|
$(DESTDIR)$(PREFIX)/bin/dmenu_path\
|
||||||
|
$(DESTDIR)$(PREFIX)/bin/dmenu_run\
|
||||||
|
$(DESTDIR)$(PREFIX)/bin/stest\
|
||||||
|
$(DESTDIR)$(MANPREFIX)/man1/dmenu.1\
|
||||||
|
$(DESTDIR)$(MANPREFIX)/man1/stest.1
|
||||||
|
|
||||||
|
.PHONY: all options clean dist install uninstall
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
dmenu - dynamic menu
|
||||||
|
====================
|
||||||
|
dmenu is an efficient dynamic menu for X.
|
||||||
|
|
||||||
|
|
||||||
|
Requirements
|
||||||
|
------------
|
||||||
|
In order to build dmenu you need the Xlib header files.
|
||||||
|
|
||||||
|
|
||||||
|
Installation
|
||||||
|
------------
|
||||||
|
Edit config.mk to match your local setup (dmenu is installed into
|
||||||
|
the /usr/local namespace by default).
|
||||||
|
|
||||||
|
Afterwards enter the following command to build and install dmenu
|
||||||
|
(if necessary as root):
|
||||||
|
|
||||||
|
make clean install
|
||||||
|
|
||||||
|
|
||||||
|
Running dmenu
|
||||||
|
-------------
|
||||||
|
See the man page for details.
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
# Caleb's Fork of dmenu
|
||||||
|
dmenu - dynamic menu
|
||||||
|
====================
|
||||||
|
dmenu is an efficient dynamic menu for X.
|
||||||
|
|
||||||
|
|
||||||
|
Requirements
|
||||||
|
------------
|
||||||
|
In order to build dmenu you need the Xlib header files.
|
||||||
|
|
||||||
|
|
||||||
|
Installation
|
||||||
|
------------
|
||||||
|
Edit config.mk to match your local setup (dmenu is installed into
|
||||||
|
the /usr/local namespace by default).
|
||||||
|
|
||||||
|
Afterwards enter the following command to build and install dmenu
|
||||||
|
(if necessary as root):
|
||||||
|
|
||||||
|
make clean install
|
||||||
|
|
||||||
|
|
||||||
|
Running dmenu
|
||||||
|
-------------
|
||||||
|
See the man page for details.
|
||||||
+49
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copy me if you can.
|
||||||
|
* by 20h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ARG_H__
|
||||||
|
#define ARG_H__
|
||||||
|
|
||||||
|
extern char *argv0;
|
||||||
|
|
||||||
|
/* use main(int argc, char *argv[]) */
|
||||||
|
#define ARGBEGIN for (argv0 = *argv, argv++, argc--;\
|
||||||
|
argv[0] && argv[0][0] == '-'\
|
||||||
|
&& argv[0][1];\
|
||||||
|
argc--, argv++) {\
|
||||||
|
char argc_;\
|
||||||
|
char **argv_;\
|
||||||
|
int brk_;\
|
||||||
|
if (argv[0][1] == '-' && argv[0][2] == '\0') {\
|
||||||
|
argv++;\
|
||||||
|
argc--;\
|
||||||
|
break;\
|
||||||
|
}\
|
||||||
|
for (brk_ = 0, argv[0]++, argv_ = argv;\
|
||||||
|
argv[0][0] && !brk_;\
|
||||||
|
argv[0]++) {\
|
||||||
|
if (argv_ != argv)\
|
||||||
|
break;\
|
||||||
|
argc_ = argv[0][0];\
|
||||||
|
switch (argc_)
|
||||||
|
|
||||||
|
#define ARGEND }\
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ARGC() argc_
|
||||||
|
|
||||||
|
#define EARGF(x) ((argv[0][1] == '\0' && argv[1] == NULL)?\
|
||||||
|
((x), abort(), (char *)0) :\
|
||||||
|
(brk_ = 1, (argv[0][1] != '\0')?\
|
||||||
|
(&argv[0][1]) :\
|
||||||
|
(argc--, argv++, argv[0])))
|
||||||
|
|
||||||
|
#define ARGF() ((argv[0][1] == '\0' && argv[1] == NULL)?\
|
||||||
|
(char *)0 :\
|
||||||
|
(brk_ = 1, (argv[0][1] != '\0')?\
|
||||||
|
(&argv[0][1]) :\
|
||||||
|
(argc--, argv++, argv[0])))
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
/* Default settings; can be overriden by command line. */
|
||||||
|
|
||||||
|
static int topbar = 1; /* -b option; if 0, dmenu appears at bottom */
|
||||||
|
/* -fn option overrides fonts[0]; default X11 font or font set */
|
||||||
|
static const char *fonts[] = {
|
||||||
|
"monospace:size=10"
|
||||||
|
};
|
||||||
|
static const char *prompt = NULL; /* -p option; prompt to the left of input field */
|
||||||
|
static const char *colors[SchemeLast][2] = {
|
||||||
|
/* fg bg */
|
||||||
|
[SchemeNorm] = { "#bbbbbb", "#222222" },
|
||||||
|
[SchemeSel] = { "#eeeeee", "#005577" },
|
||||||
|
[SchemeOut] = { "#000000", "#00ffff" },
|
||||||
|
};
|
||||||
|
/* -l and -g options; controls number of lines and columns in grid if > 0 */
|
||||||
|
static unsigned int lines = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Characters not considered part of a word while deleting words
|
||||||
|
* for example: " /?\"&[]"
|
||||||
|
*/
|
||||||
|
static const char worddelimiters[] = " ";
|
||||||
|
|
||||||
|
/* Size of the window border */
|
||||||
|
static const unsigned int border_width = 5;
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
/* Default settings; can be overriden by command line. */
|
||||||
|
|
||||||
|
static int topbar = 1; /* -b option; if 0, dmenu appears at bottom */
|
||||||
|
/* -fn option overrides fonts[0]; default X11 font or font set */
|
||||||
|
static const char *fonts[] = {
|
||||||
|
"monospace:size=10"
|
||||||
|
};
|
||||||
|
static const char *prompt = NULL; /* -p option; prompt to the left of input field */
|
||||||
|
static const char *colors[SchemeLast][2] = {
|
||||||
|
/* fg bg */
|
||||||
|
[SchemeNorm] = { "#bbbbbb", "#222222" },
|
||||||
|
[SchemeSel] = { "#eeeeee", "#005577" },
|
||||||
|
[SchemeOut] = { "#000000", "#00ffff" },
|
||||||
|
};
|
||||||
|
/* -l and -g options; controls number of lines and columns in grid if > 0 */
|
||||||
|
static unsigned int lines = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Characters not considered part of a word while deleting words
|
||||||
|
* for example: " /?\"&[]"
|
||||||
|
*/
|
||||||
|
static const char worddelimiters[] = " ";
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
--- config.def.h
|
||||||
|
+++ config.def.h
|
||||||
|
@@ -14,6 +15,13 @@ static const char *colors[SchemeLast][2] = {
|
||||||
|
[SchemeSel] = { "#eeeeee", "#005577" },
|
||||||
|
[SchemeOut] = { "#000000", "#00ffff" },
|
||||||
|
};
|
||||||
|
+
|
||||||
|
+static const unsigned int alphas[SchemeLast][2] = {
|
||||||
|
+ [SchemeNorm] = { OPAQUE, alpha },
|
||||||
|
+ [SchemeSel] = { OPAQUE, alpha },
|
||||||
|
+ [SchemeOut] = { OPAQUE, alpha },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
/* -l option; if nonzero, dmenu uses vertical list with given number of lines */
|
||||||
|
static unsigned int lines = 0;
|
||||||
|
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
/* Default settings; can be overriden by command line. */
|
||||||
|
|
||||||
|
static int topbar = 1; /* -b option; if 0, dmenu appears at bottom */
|
||||||
|
static const unsigned int alpha = 0xf0;
|
||||||
|
|
||||||
|
/* -fn option overrides fonts[0]; default X11 font or font set */
|
||||||
|
static const char *fonts[] = {
|
||||||
|
"monospace:size=10"
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *prompt = NULL; /* -p option; prompt to the left of input field */
|
||||||
|
static const char *colors[SchemeLast][2] = {
|
||||||
|
/* fg bg */
|
||||||
|
[SchemeNorm] = { "#bbbbbb", "#222222" },
|
||||||
|
[SchemeSel] = { "#eeeeee", "#005577" },
|
||||||
|
[SchemeOut] = { "#000000", "#00ffff" },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const unsigned int alphas[SchemeLast][2] = {
|
||||||
|
[SchemeNorm] = { OPAQUE, alpha },
|
||||||
|
[SchemeSel] = { OPAQUE, alpha },
|
||||||
|
[SchemeOut] = { OPAQUE, alpha },
|
||||||
|
};
|
||||||
|
|
||||||
|
/* -l option; if nonzero, dmenu uses vertical list with given number of lines */
|
||||||
|
static unsigned int lines = 10;
|
||||||
|
static unsigned int columns = 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Characters not considered part of a word while deleting words
|
||||||
|
* for example: " /?\"&[]"
|
||||||
|
*/
|
||||||
|
static const char worddelimiters[] = " ";
|
||||||
|
|
||||||
|
/* Size of the window border */
|
||||||
|
static const unsigned int border_width = 0;
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
# dmenu version
|
||||||
|
VERSION = 5.0
|
||||||
|
|
||||||
|
# paths
|
||||||
|
PREFIX = /usr/local
|
||||||
|
MANPREFIX = $(PREFIX)/share/man
|
||||||
|
|
||||||
|
X11INC = /usr/X11R6/include
|
||||||
|
X11LIB = /usr/X11R6/lib
|
||||||
|
|
||||||
|
# Xinerama, comment if you don't want it
|
||||||
|
XINERAMALIBS = -lXinerama
|
||||||
|
XINERAMAFLAGS = -DXINERAMA
|
||||||
|
|
||||||
|
# freetype
|
||||||
|
FREETYPELIBS = -lfontconfig -lXft
|
||||||
|
FREETYPEINC = /usr/include/freetype2
|
||||||
|
# OpenBSD (uncomment)
|
||||||
|
#FREETYPEINC = $(X11INC)/freetype2
|
||||||
|
|
||||||
|
# includes and libs
|
||||||
|
INCS = -I$(X11INC) -I$(FREETYPEINC)
|
||||||
|
LIBS = -L$(X11LIB) -lX11 $(XINERAMALIBS) $(FREETYPELIBS) -lXrender
|
||||||
|
|
||||||
|
# flags
|
||||||
|
CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" $(XINERAMAFLAGS)
|
||||||
|
CFLAGS = -std=c99 -pedantic -Wall -Os $(INCS) $(CPPFLAGS)
|
||||||
|
LDFLAGS = $(LIBS)
|
||||||
|
|
||||||
|
# compiler and linker
|
||||||
|
CC = cc
|
||||||
+199
@@ -0,0 +1,199 @@
|
|||||||
|
.TH DMENU 1 dmenu\-VERSION
|
||||||
|
.SH NAME
|
||||||
|
dmenu \- dynamic menu
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B dmenu
|
||||||
|
.RB [ \-bfiv ]
|
||||||
|
.RB [ \-g
|
||||||
|
.IR columns ]
|
||||||
|
.RB [ \-l
|
||||||
|
.IR lines ]
|
||||||
|
.RB [ \-m
|
||||||
|
.IR monitor ]
|
||||||
|
.RB [ \-p
|
||||||
|
.IR prompt ]
|
||||||
|
.RB [ \-fn
|
||||||
|
.IR font ]
|
||||||
|
.RB [ \-nb
|
||||||
|
.IR color ]
|
||||||
|
.RB [ \-nf
|
||||||
|
.IR color ]
|
||||||
|
.RB [ \-sb
|
||||||
|
.IR color ]
|
||||||
|
.RB [ \-sf
|
||||||
|
.IR color ]
|
||||||
|
.RB [ \-w
|
||||||
|
.IR windowid ]
|
||||||
|
.P
|
||||||
|
.BR dmenu_run " ..."
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.B dmenu
|
||||||
|
is a dynamic menu for X, which reads a list of newline\-separated items from
|
||||||
|
stdin. When the user selects an item and presses Return, their choice is printed
|
||||||
|
to stdout and dmenu terminates. Entering text will narrow the items to those
|
||||||
|
matching the tokens in the input.
|
||||||
|
.P
|
||||||
|
.B dmenu_run
|
||||||
|
is a script used by
|
||||||
|
.IR dwm (1)
|
||||||
|
which lists programs in the user's $PATH and runs the result in their $SHELL.
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
.B \-b
|
||||||
|
dmenu appears at the bottom of the screen.
|
||||||
|
.TP
|
||||||
|
.B \-f
|
||||||
|
dmenu grabs the keyboard before reading stdin if not reading from a tty. This
|
||||||
|
is faster, but will lock up X until stdin reaches end\-of\-file.
|
||||||
|
.TP
|
||||||
|
.B \-i
|
||||||
|
dmenu matches menu items case insensitively.
|
||||||
|
.TP
|
||||||
|
.BI \-g " columns"
|
||||||
|
dmenu lists items in a grid with the given number of columns.
|
||||||
|
.TP
|
||||||
|
.BI \-l " lines"
|
||||||
|
dmenu lists items in a grid with the given number of lines.
|
||||||
|
.TP
|
||||||
|
.BI \-m " monitor"
|
||||||
|
dmenu is displayed on the monitor number supplied. Monitor numbers are starting
|
||||||
|
from 0.
|
||||||
|
.TP
|
||||||
|
.BI \-p " prompt"
|
||||||
|
defines the prompt to be displayed to the left of the input field.
|
||||||
|
.TP
|
||||||
|
.BI \-fn " font"
|
||||||
|
defines the font or font set used.
|
||||||
|
.TP
|
||||||
|
.BI \-nb " color"
|
||||||
|
defines the normal background color.
|
||||||
|
.IR #RGB ,
|
||||||
|
.IR #RRGGBB ,
|
||||||
|
and X color names are supported.
|
||||||
|
.TP
|
||||||
|
.BI \-nf " color"
|
||||||
|
defines the normal foreground color.
|
||||||
|
.TP
|
||||||
|
.BI \-sb " color"
|
||||||
|
defines the selected background color.
|
||||||
|
.TP
|
||||||
|
.BI \-sf " color"
|
||||||
|
defines the selected foreground color.
|
||||||
|
.TP
|
||||||
|
.B \-v
|
||||||
|
prints version information to stdout, then exits.
|
||||||
|
.TP
|
||||||
|
.BI \-w " windowid"
|
||||||
|
embed into windowid.
|
||||||
|
.SH USAGE
|
||||||
|
dmenu is completely controlled by the keyboard. Items are selected using the
|
||||||
|
arrow keys, page up, page down, home, and end.
|
||||||
|
.TP
|
||||||
|
.B Tab
|
||||||
|
Copy the selected item to the input field.
|
||||||
|
.TP
|
||||||
|
.B Return
|
||||||
|
Confirm selection. Prints the selected item to stdout and exits, returning
|
||||||
|
success.
|
||||||
|
.TP
|
||||||
|
.B Ctrl-Return
|
||||||
|
Confirm selection. Prints the selected item to stdout and continues.
|
||||||
|
.TP
|
||||||
|
.B Shift\-Return
|
||||||
|
Confirm input. Prints the input text to stdout and exits, returning success.
|
||||||
|
.TP
|
||||||
|
.B Escape
|
||||||
|
Exit without selecting an item, returning failure.
|
||||||
|
.TP
|
||||||
|
.B Ctrl-Left
|
||||||
|
Move cursor to the start of the current word
|
||||||
|
.TP
|
||||||
|
.B Ctrl-Right
|
||||||
|
Move cursor to the end of the current word
|
||||||
|
.TP
|
||||||
|
.B C\-a
|
||||||
|
Home
|
||||||
|
.TP
|
||||||
|
.B C\-b
|
||||||
|
Left
|
||||||
|
.TP
|
||||||
|
.B C\-c
|
||||||
|
Escape
|
||||||
|
.TP
|
||||||
|
.B C\-d
|
||||||
|
Delete
|
||||||
|
.TP
|
||||||
|
.B C\-e
|
||||||
|
End
|
||||||
|
.TP
|
||||||
|
.B C\-f
|
||||||
|
Right
|
||||||
|
.TP
|
||||||
|
.B C\-g
|
||||||
|
Escape
|
||||||
|
.TP
|
||||||
|
.B C\-h
|
||||||
|
Backspace
|
||||||
|
.TP
|
||||||
|
.B C\-i
|
||||||
|
Tab
|
||||||
|
.TP
|
||||||
|
.B C\-j
|
||||||
|
Return
|
||||||
|
.TP
|
||||||
|
.B C\-J
|
||||||
|
Shift-Return
|
||||||
|
.TP
|
||||||
|
.B C\-k
|
||||||
|
Delete line right
|
||||||
|
.TP
|
||||||
|
.B C\-m
|
||||||
|
Return
|
||||||
|
.TP
|
||||||
|
.B C\-M
|
||||||
|
Shift-Return
|
||||||
|
.TP
|
||||||
|
.B C\-n
|
||||||
|
Down
|
||||||
|
.TP
|
||||||
|
.B C\-p
|
||||||
|
Up
|
||||||
|
.TP
|
||||||
|
.B C\-u
|
||||||
|
Delete line left
|
||||||
|
.TP
|
||||||
|
.B C\-w
|
||||||
|
Delete word left
|
||||||
|
.TP
|
||||||
|
.B C\-y
|
||||||
|
Paste from primary X selection
|
||||||
|
.TP
|
||||||
|
.B C\-Y
|
||||||
|
Paste from X clipboard
|
||||||
|
.TP
|
||||||
|
.B M\-b
|
||||||
|
Move cursor to the start of the current word
|
||||||
|
.TP
|
||||||
|
.B M\-f
|
||||||
|
Move cursor to the end of the current word
|
||||||
|
.TP
|
||||||
|
.B M\-g
|
||||||
|
Home
|
||||||
|
.TP
|
||||||
|
.B M\-G
|
||||||
|
End
|
||||||
|
.TP
|
||||||
|
.B M\-h
|
||||||
|
Up
|
||||||
|
.TP
|
||||||
|
.B M\-j
|
||||||
|
Page down
|
||||||
|
.TP
|
||||||
|
.B M\-k
|
||||||
|
Page up
|
||||||
|
.TP
|
||||||
|
.B M\-l
|
||||||
|
Down
|
||||||
|
.SH SEE ALSO
|
||||||
|
.IR dwm (1),
|
||||||
|
.IR stest (1)
|
||||||
+850
@@ -0,0 +1,850 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <locale.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <strings.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include <X11/Xatom.h>
|
||||||
|
#include <X11/Xproto.h>
|
||||||
|
#include <X11/Xutil.h>
|
||||||
|
#ifdef XINERAMA
|
||||||
|
#include <X11/extensions/Xinerama.h>
|
||||||
|
#endif
|
||||||
|
#include <X11/Xft/Xft.h>
|
||||||
|
|
||||||
|
#include "drw.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
/* macros */
|
||||||
|
#define INTERSECT(x,y,w,h,r) (MAX(0, MIN((x)+(w),(r).x_org+(r).width) - MAX((x),(r).x_org)) \
|
||||||
|
* MAX(0, MIN((y)+(h),(r).y_org+(r).height) - MAX((y),(r).y_org)))
|
||||||
|
#define LENGTH(X) (sizeof X / sizeof X[0])
|
||||||
|
#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
|
||||||
|
|
||||||
|
#define OPAQUE 0xffU
|
||||||
|
|
||||||
|
/* enums */
|
||||||
|
enum { SchemeNorm, SchemeSel, SchemeOut, SchemeLast }; /* color schemes */
|
||||||
|
|
||||||
|
struct item {
|
||||||
|
char *text;
|
||||||
|
struct item *left, *right;
|
||||||
|
int out;
|
||||||
|
};
|
||||||
|
|
||||||
|
static char text[BUFSIZ] = "";
|
||||||
|
static char *embed;
|
||||||
|
static int bh, mw, mh;
|
||||||
|
static int inputw = 0, promptw;
|
||||||
|
static int lrpad; /* sum of left and right padding */
|
||||||
|
static size_t cursor;
|
||||||
|
static struct item *items = NULL;
|
||||||
|
static struct item *matches, *matchend;
|
||||||
|
static struct item *prev, *curr, *next, *sel;
|
||||||
|
static int mon = -1, screen;
|
||||||
|
|
||||||
|
static Atom clip, utf8;
|
||||||
|
static Display *dpy;
|
||||||
|
static Window root, parentwin, win;
|
||||||
|
static XIC xic;
|
||||||
|
|
||||||
|
static Drw *drw;
|
||||||
|
static Clr *scheme[SchemeLast];
|
||||||
|
|
||||||
|
static int useargb = 0;
|
||||||
|
static Visual *visual;
|
||||||
|
static int depth;
|
||||||
|
static Colormap cmap;
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
static int (*fstrncmp)(const char *, const char *, size_t) = strncmp;
|
||||||
|
static char *(*fstrstr)(const char *, const char *) = strstr;
|
||||||
|
static void xinitvisual();
|
||||||
|
|
||||||
|
static void
|
||||||
|
appenditem(struct item *item, struct item **list, struct item **last)
|
||||||
|
{
|
||||||
|
if (*last)
|
||||||
|
(*last)->right = item;
|
||||||
|
else
|
||||||
|
*list = item;
|
||||||
|
|
||||||
|
item->left = *last;
|
||||||
|
item->right = NULL;
|
||||||
|
*last = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
calcoffsets(void)
|
||||||
|
{
|
||||||
|
int i, n;
|
||||||
|
|
||||||
|
if (lines > 0)
|
||||||
|
n = lines * columns * bh;
|
||||||
|
else
|
||||||
|
n = mw - (promptw + inputw + TEXTW("<") + TEXTW(">"));
|
||||||
|
/* calculate which items will begin the next page and previous page */
|
||||||
|
for (i = 0, next = curr; next; next = next->right)
|
||||||
|
if ((i += (lines > 0) ? bh : MIN(TEXTW(next->text), n)) > n)
|
||||||
|
break;
|
||||||
|
for (i = 0, prev = curr; prev && prev->left; prev = prev->left)
|
||||||
|
if ((i += (lines > 0) ? bh : MIN(TEXTW(prev->left->text), n)) > n)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
max_textw(void)
|
||||||
|
{
|
||||||
|
int len = 0;
|
||||||
|
for (struct item *item = items; item && item->text; item++)
|
||||||
|
len = MAX(TEXTW(item->text), len);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cleanup(void)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
XUngrabKey(dpy, AnyKey, AnyModifier, root);
|
||||||
|
for (i = 0; i < SchemeLast; i++)
|
||||||
|
free(scheme[i]);
|
||||||
|
drw_free(drw);
|
||||||
|
XSync(dpy, False);
|
||||||
|
XCloseDisplay(dpy);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
cistrstr(const char *s, const char *sub)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
for (len = strlen(sub); *s; s++)
|
||||||
|
if (!strncasecmp(s, sub, len))
|
||||||
|
return (char *)s;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
drawitem(struct item *item, int x, int y, int w)
|
||||||
|
{
|
||||||
|
if (item == sel)
|
||||||
|
drw_setscheme(drw, scheme[SchemeSel]);
|
||||||
|
else if (item->out)
|
||||||
|
drw_setscheme(drw, scheme[SchemeOut]);
|
||||||
|
else
|
||||||
|
drw_setscheme(drw, scheme[SchemeNorm]);
|
||||||
|
|
||||||
|
return drw_text(drw, x, y, w, bh, lrpad / 2, item->text, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
drawmenu(void)
|
||||||
|
{
|
||||||
|
unsigned int curpos;
|
||||||
|
struct item *item;
|
||||||
|
int x = 0, y = 0, w;
|
||||||
|
|
||||||
|
drw_setscheme(drw, scheme[SchemeNorm]);
|
||||||
|
drw_rect(drw, 0, 0, mw, mh, 1, 1);
|
||||||
|
|
||||||
|
if (prompt && *prompt) {
|
||||||
|
drw_setscheme(drw, scheme[SchemeSel]);
|
||||||
|
x = drw_text(drw, x, 0, promptw, bh, lrpad / 2, prompt, 0);
|
||||||
|
}
|
||||||
|
/* draw input field */
|
||||||
|
w = (lines > 0 || !matches) ? mw - x : inputw;
|
||||||
|
drw_setscheme(drw, scheme[SchemeNorm]);
|
||||||
|
drw_text(drw, x, 0, w, bh, lrpad / 2, text, 0);
|
||||||
|
|
||||||
|
curpos = TEXTW(text) - TEXTW(&text[cursor]);
|
||||||
|
if ((curpos += lrpad / 2 - 1) < w) {
|
||||||
|
drw_setscheme(drw, scheme[SchemeNorm]);
|
||||||
|
drw_rect(drw, x + curpos, 2, 2, bh - 4, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lines > 0) {
|
||||||
|
/* draw grid */
|
||||||
|
int i = 0;
|
||||||
|
for (item = curr; item != next; item = item->right, i++)
|
||||||
|
drawitem(
|
||||||
|
item,
|
||||||
|
x + ((i / lines) * ((mw - x) / columns)),
|
||||||
|
y + (((i % lines) + 1) * bh),
|
||||||
|
(mw - x) / columns
|
||||||
|
);
|
||||||
|
} else if (matches) {
|
||||||
|
/* draw horizontal list */
|
||||||
|
x += inputw;
|
||||||
|
w = TEXTW("<");
|
||||||
|
if (curr->left) {
|
||||||
|
drw_setscheme(drw, scheme[SchemeNorm]);
|
||||||
|
drw_text(drw, x, 0, w, bh, lrpad / 2, "<", 0);
|
||||||
|
}
|
||||||
|
x += w;
|
||||||
|
for (item = curr; item != next; item = item->right)
|
||||||
|
x = drawitem(item, x, 0, MIN(TEXTW(item->text), mw - x - TEXTW(">")));
|
||||||
|
if (next) {
|
||||||
|
w = TEXTW(">");
|
||||||
|
drw_setscheme(drw, scheme[SchemeNorm]);
|
||||||
|
drw_text(drw, mw - w, 0, w, bh, lrpad / 2, ">", 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
drw_map(drw, win, 0, 0, mw, mh);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
grabfocus(void)
|
||||||
|
{
|
||||||
|
struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000 };
|
||||||
|
Window focuswin;
|
||||||
|
int i, revertwin;
|
||||||
|
|
||||||
|
for (i = 0; i < 100; ++i) {
|
||||||
|
XGetInputFocus(dpy, &focuswin, &revertwin);
|
||||||
|
if (focuswin == win)
|
||||||
|
return;
|
||||||
|
XSetInputFocus(dpy, win, RevertToParent, CurrentTime);
|
||||||
|
nanosleep(&ts, NULL);
|
||||||
|
}
|
||||||
|
die("cannot grab focus");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
grabkeyboard(void)
|
||||||
|
{
|
||||||
|
struct timespec ts = { .tv_sec = 0, .tv_nsec = 1000000 };
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (embed)
|
||||||
|
return;
|
||||||
|
/* try to grab keyboard, we may have to wait for another process to ungrab */
|
||||||
|
for (i = 0; i < 1000; i++) {
|
||||||
|
if (XGrabKeyboard(dpy, DefaultRootWindow(dpy), True, GrabModeAsync,
|
||||||
|
GrabModeAsync, CurrentTime) == GrabSuccess)
|
||||||
|
return;
|
||||||
|
nanosleep(&ts, NULL);
|
||||||
|
}
|
||||||
|
die("cannot grab keyboard");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
match(void)
|
||||||
|
{
|
||||||
|
static char **tokv = NULL;
|
||||||
|
static int tokn = 0;
|
||||||
|
|
||||||
|
char buf[sizeof text], *s;
|
||||||
|
int i, tokc = 0;
|
||||||
|
size_t len, textsize;
|
||||||
|
struct item *item, *lprefix, *lsubstr, *prefixend, *substrend;
|
||||||
|
|
||||||
|
strcpy(buf, text);
|
||||||
|
/* separate input text into tokens to be matched individually */
|
||||||
|
for (s = strtok(buf, " "); s; tokv[tokc - 1] = s, s = strtok(NULL, " "))
|
||||||
|
if (++tokc > tokn && !(tokv = realloc(tokv, ++tokn * sizeof *tokv)))
|
||||||
|
die("cannot realloc %u bytes:", tokn * sizeof *tokv);
|
||||||
|
len = tokc ? strlen(tokv[0]) : 0;
|
||||||
|
|
||||||
|
matches = lprefix = lsubstr = matchend = prefixend = substrend = NULL;
|
||||||
|
textsize = strlen(text) + 1;
|
||||||
|
for (item = items; item && item->text; item++) {
|
||||||
|
for (i = 0; i < tokc; i++)
|
||||||
|
if (!fstrstr(item->text, tokv[i]))
|
||||||
|
break;
|
||||||
|
if (i != tokc) /* not all tokens match */
|
||||||
|
continue;
|
||||||
|
/* exact matches go first, then prefixes, then substrings */
|
||||||
|
if (!tokc || !fstrncmp(text, item->text, textsize))
|
||||||
|
appenditem(item, &matches, &matchend);
|
||||||
|
else if (!fstrncmp(tokv[0], item->text, len))
|
||||||
|
appenditem(item, &lprefix, &prefixend);
|
||||||
|
else
|
||||||
|
appenditem(item, &lsubstr, &substrend);
|
||||||
|
}
|
||||||
|
if (lprefix) {
|
||||||
|
if (matches) {
|
||||||
|
matchend->right = lprefix;
|
||||||
|
lprefix->left = matchend;
|
||||||
|
} else
|
||||||
|
matches = lprefix;
|
||||||
|
matchend = prefixend;
|
||||||
|
}
|
||||||
|
if (lsubstr) {
|
||||||
|
if (matches) {
|
||||||
|
matchend->right = lsubstr;
|
||||||
|
lsubstr->left = matchend;
|
||||||
|
} else
|
||||||
|
matches = lsubstr;
|
||||||
|
matchend = substrend;
|
||||||
|
}
|
||||||
|
curr = sel = matches;
|
||||||
|
calcoffsets();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
insert(const char *str, ssize_t n)
|
||||||
|
{
|
||||||
|
if (strlen(text) + n > sizeof text - 1)
|
||||||
|
return;
|
||||||
|
/* move existing text out of the way, insert new text, and update cursor */
|
||||||
|
memmove(&text[cursor + n], &text[cursor], sizeof text - cursor - MAX(n, 0));
|
||||||
|
if (n > 0)
|
||||||
|
memcpy(&text[cursor], str, n);
|
||||||
|
cursor += n;
|
||||||
|
match();
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
nextrune(int inc)
|
||||||
|
{
|
||||||
|
ssize_t n;
|
||||||
|
|
||||||
|
/* return location of next utf8 rune in the given direction (+1 or -1) */
|
||||||
|
for (n = cursor + inc; n + inc >= 0 && (text[n] & 0xc0) == 0x80; n += inc)
|
||||||
|
;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
movewordedge(int dir)
|
||||||
|
{
|
||||||
|
if (dir < 0) { /* move cursor to the start of the word*/
|
||||||
|
while (cursor > 0 && strchr(worddelimiters, text[nextrune(-1)]))
|
||||||
|
cursor = nextrune(-1);
|
||||||
|
while (cursor > 0 && !strchr(worddelimiters, text[nextrune(-1)]))
|
||||||
|
cursor = nextrune(-1);
|
||||||
|
} else { /* move cursor to the end of the word */
|
||||||
|
while (text[cursor] && strchr(worddelimiters, text[cursor]))
|
||||||
|
cursor = nextrune(+1);
|
||||||
|
while (text[cursor] && !strchr(worddelimiters, text[cursor]))
|
||||||
|
cursor = nextrune(+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
keypress(XKeyEvent *ev)
|
||||||
|
{
|
||||||
|
char buf[32];
|
||||||
|
int len;
|
||||||
|
KeySym ksym;
|
||||||
|
Status status;
|
||||||
|
|
||||||
|
len = XmbLookupString(xic, ev, buf, sizeof buf, &ksym, &status);
|
||||||
|
switch (status) {
|
||||||
|
default: /* XLookupNone, XBufferOverflow */
|
||||||
|
return;
|
||||||
|
case XLookupChars:
|
||||||
|
goto insert;
|
||||||
|
case XLookupKeySym:
|
||||||
|
case XLookupBoth:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ev->state & ControlMask) {
|
||||||
|
switch(ksym) {
|
||||||
|
case XK_a: ksym = XK_Home; break;
|
||||||
|
case XK_b: ksym = XK_Left; break;
|
||||||
|
case XK_c: ksym = XK_Escape; break;
|
||||||
|
case XK_d: ksym = XK_Delete; break;
|
||||||
|
case XK_e: ksym = XK_End; break;
|
||||||
|
case XK_f: ksym = XK_Right; break;
|
||||||
|
case XK_g: ksym = XK_Escape; break;
|
||||||
|
case XK_h: ksym = XK_BackSpace; break;
|
||||||
|
case XK_i: ksym = XK_Tab; break;
|
||||||
|
case XK_j: /* fallthrough */
|
||||||
|
case XK_J: /* fallthrough */
|
||||||
|
case XK_m: /* fallthrough */
|
||||||
|
case XK_M: ksym = XK_Return; ev->state &= ~ControlMask; break;
|
||||||
|
case XK_n: ksym = XK_Down; break;
|
||||||
|
case XK_p: ksym = XK_Up; break;
|
||||||
|
|
||||||
|
case XK_k: /* delete right */
|
||||||
|
text[cursor] = '\0';
|
||||||
|
match();
|
||||||
|
break;
|
||||||
|
case XK_u: /* delete left */
|
||||||
|
insert(NULL, 0 - cursor);
|
||||||
|
break;
|
||||||
|
case XK_w: /* delete word */
|
||||||
|
while (cursor > 0 && strchr(worddelimiters, text[nextrune(-1)]))
|
||||||
|
insert(NULL, nextrune(-1) - cursor);
|
||||||
|
while (cursor > 0 && !strchr(worddelimiters, text[nextrune(-1)]))
|
||||||
|
insert(NULL, nextrune(-1) - cursor);
|
||||||
|
break;
|
||||||
|
case XK_y: /* paste selection */
|
||||||
|
case XK_Y:
|
||||||
|
XConvertSelection(dpy, (ev->state & ShiftMask) ? clip : XA_PRIMARY,
|
||||||
|
utf8, utf8, win, CurrentTime);
|
||||||
|
return;
|
||||||
|
case XK_Left:
|
||||||
|
case XK_KP_Left:
|
||||||
|
movewordedge(-1);
|
||||||
|
goto draw;
|
||||||
|
case XK_Right:
|
||||||
|
case XK_KP_Right:
|
||||||
|
movewordedge(+1);
|
||||||
|
goto draw;
|
||||||
|
case XK_Return:
|
||||||
|
case XK_KP_Enter:
|
||||||
|
break;
|
||||||
|
case XK_bracketleft:
|
||||||
|
cleanup();
|
||||||
|
exit(1);
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (ev->state & Mod1Mask) {
|
||||||
|
switch(ksym) {
|
||||||
|
case XK_b:
|
||||||
|
movewordedge(-1);
|
||||||
|
goto draw;
|
||||||
|
case XK_f:
|
||||||
|
movewordedge(+1);
|
||||||
|
goto draw;
|
||||||
|
case XK_g: ksym = XK_Home; break;
|
||||||
|
case XK_G: ksym = XK_End; break;
|
||||||
|
case XK_h: ksym = XK_Up; break;
|
||||||
|
case XK_j: ksym = XK_Next; break;
|
||||||
|
case XK_k: ksym = XK_Prior; break;
|
||||||
|
case XK_l: ksym = XK_Down; break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(ksym) {
|
||||||
|
default:
|
||||||
|
insert:
|
||||||
|
if (!iscntrl(*buf))
|
||||||
|
insert(buf, len);
|
||||||
|
break;
|
||||||
|
case XK_Delete:
|
||||||
|
case XK_KP_Delete:
|
||||||
|
if (text[cursor] == '\0')
|
||||||
|
return;
|
||||||
|
cursor = nextrune(+1);
|
||||||
|
/* fallthrough */
|
||||||
|
case XK_BackSpace:
|
||||||
|
if (cursor == 0)
|
||||||
|
return;
|
||||||
|
insert(NULL, nextrune(-1) - cursor);
|
||||||
|
break;
|
||||||
|
case XK_End:
|
||||||
|
case XK_KP_End:
|
||||||
|
if (text[cursor] != '\0') {
|
||||||
|
cursor = strlen(text);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (next) {
|
||||||
|
/* jump to end of list and position items in reverse */
|
||||||
|
curr = matchend;
|
||||||
|
calcoffsets();
|
||||||
|
curr = prev;
|
||||||
|
calcoffsets();
|
||||||
|
while (next && (curr = curr->right))
|
||||||
|
calcoffsets();
|
||||||
|
}
|
||||||
|
sel = matchend;
|
||||||
|
break;
|
||||||
|
case XK_Escape:
|
||||||
|
cleanup();
|
||||||
|
exit(1);
|
||||||
|
case XK_Home:
|
||||||
|
case XK_KP_Home:
|
||||||
|
if (sel == matches) {
|
||||||
|
cursor = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sel = curr = matches;
|
||||||
|
calcoffsets();
|
||||||
|
break;
|
||||||
|
case XK_Left:
|
||||||
|
case XK_KP_Left:
|
||||||
|
if (cursor > 0 && (!sel || !sel->left || lines > 0)) {
|
||||||
|
cursor = nextrune(-1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (lines > 0)
|
||||||
|
return;
|
||||||
|
/* fallthrough */
|
||||||
|
case XK_Up:
|
||||||
|
case XK_KP_Up:
|
||||||
|
if (sel && sel->left && (sel = sel->left)->right == curr) {
|
||||||
|
curr = prev;
|
||||||
|
calcoffsets();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case XK_Next:
|
||||||
|
case XK_KP_Next:
|
||||||
|
if (!next)
|
||||||
|
return;
|
||||||
|
sel = curr = next;
|
||||||
|
calcoffsets();
|
||||||
|
break;
|
||||||
|
case XK_Prior:
|
||||||
|
case XK_KP_Prior:
|
||||||
|
if (!prev)
|
||||||
|
return;
|
||||||
|
sel = curr = prev;
|
||||||
|
calcoffsets();
|
||||||
|
break;
|
||||||
|
case XK_Return:
|
||||||
|
case XK_KP_Enter:
|
||||||
|
puts((sel && !(ev->state & ShiftMask)) ? sel->text : text);
|
||||||
|
if (!(ev->state & ControlMask)) {
|
||||||
|
cleanup();
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
if (sel)
|
||||||
|
sel->out = 1;
|
||||||
|
break;
|
||||||
|
case XK_Right:
|
||||||
|
case XK_KP_Right:
|
||||||
|
if (text[cursor] != '\0') {
|
||||||
|
cursor = nextrune(+1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (lines > 0)
|
||||||
|
return;
|
||||||
|
/* fallthrough */
|
||||||
|
case XK_Down:
|
||||||
|
case XK_KP_Down:
|
||||||
|
if (sel && sel->right && (sel = sel->right) == next) {
|
||||||
|
curr = next;
|
||||||
|
calcoffsets();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case XK_Tab:
|
||||||
|
if (!sel)
|
||||||
|
return;
|
||||||
|
strncpy(text, sel->text, sizeof text - 1);
|
||||||
|
text[sizeof text - 1] = '\0';
|
||||||
|
cursor = strlen(text);
|
||||||
|
match();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
draw:
|
||||||
|
drawmenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
paste(void)
|
||||||
|
{
|
||||||
|
char *p, *q;
|
||||||
|
int di;
|
||||||
|
unsigned long dl;
|
||||||
|
Atom da;
|
||||||
|
|
||||||
|
/* we have been given the current selection, now insert it into input */
|
||||||
|
if (XGetWindowProperty(dpy, win, utf8, 0, (sizeof text / 4) + 1, False,
|
||||||
|
utf8, &da, &di, &dl, &dl, (unsigned char **)&p)
|
||||||
|
== Success && p) {
|
||||||
|
insert(p, (q = strchr(p, '\n')) ? q - p : (ssize_t)strlen(p));
|
||||||
|
XFree(p);
|
||||||
|
}
|
||||||
|
drawmenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
readstdin(void)
|
||||||
|
{
|
||||||
|
char buf[sizeof text], *p;
|
||||||
|
size_t i, imax = 0, size = 0;
|
||||||
|
unsigned int tmpmax = 0;
|
||||||
|
|
||||||
|
/* read each line from stdin and add it to the item list */
|
||||||
|
for (i = 0; fgets(buf, sizeof buf, stdin); i++) {
|
||||||
|
if (i + 1 >= size / sizeof *items)
|
||||||
|
if (!(items = realloc(items, (size += BUFSIZ))))
|
||||||
|
die("cannot realloc %u bytes:", size);
|
||||||
|
if ((p = strchr(buf, '\n')))
|
||||||
|
*p = '\0';
|
||||||
|
if (!(items[i].text = strdup(buf)))
|
||||||
|
die("cannot strdup %u bytes:", strlen(buf) + 1);
|
||||||
|
items[i].out = 0;
|
||||||
|
drw_font_getexts(drw->fonts, buf, strlen(buf), &tmpmax, NULL);
|
||||||
|
if (tmpmax > inputw) {
|
||||||
|
inputw = tmpmax;
|
||||||
|
imax = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (items)
|
||||||
|
items[i].text = NULL;
|
||||||
|
inputw = items ? TEXTW(items[imax].text) : 0;
|
||||||
|
lines = MIN(lines, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
run(void)
|
||||||
|
{
|
||||||
|
XEvent ev;
|
||||||
|
|
||||||
|
while (!XNextEvent(dpy, &ev)) {
|
||||||
|
if (XFilterEvent(&ev, win))
|
||||||
|
continue;
|
||||||
|
switch(ev.type) {
|
||||||
|
case DestroyNotify:
|
||||||
|
if (ev.xdestroywindow.window != win)
|
||||||
|
break;
|
||||||
|
cleanup();
|
||||||
|
exit(1);
|
||||||
|
case Expose:
|
||||||
|
if (ev.xexpose.count == 0)
|
||||||
|
drw_map(drw, win, 0, 0, mw, mh);
|
||||||
|
break;
|
||||||
|
case FocusIn:
|
||||||
|
/* regrab focus from parent window */
|
||||||
|
if (ev.xfocus.window != win)
|
||||||
|
grabfocus();
|
||||||
|
break;
|
||||||
|
case KeyPress:
|
||||||
|
keypress(&ev.xkey);
|
||||||
|
break;
|
||||||
|
case SelectionNotify:
|
||||||
|
if (ev.xselection.property == utf8)
|
||||||
|
paste();
|
||||||
|
break;
|
||||||
|
case VisibilityNotify:
|
||||||
|
if (ev.xvisibility.state != VisibilityUnobscured)
|
||||||
|
XRaiseWindow(dpy, win);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
setup(void)
|
||||||
|
{
|
||||||
|
int x, y, i, j;
|
||||||
|
unsigned int du;
|
||||||
|
XSetWindowAttributes swa;
|
||||||
|
XIM xim;
|
||||||
|
Window w, dw, *dws;
|
||||||
|
XWindowAttributes wa;
|
||||||
|
XClassHint ch = {"dmenu", "dmenu"};
|
||||||
|
#ifdef XINERAMA
|
||||||
|
XineramaScreenInfo *info;
|
||||||
|
Window pw;
|
||||||
|
int a, di, n, area = 0;
|
||||||
|
#endif
|
||||||
|
/* init appearance */
|
||||||
|
for (j = 0; j < SchemeLast; j++)
|
||||||
|
scheme[j] = drw_scm_create(drw, colors[j], alphas[i], 2);
|
||||||
|
|
||||||
|
clip = XInternAtom(dpy, "CLIPBOARD", False);
|
||||||
|
utf8 = XInternAtom(dpy, "UTF8_STRING", False);
|
||||||
|
|
||||||
|
/* calculate menu geometry */
|
||||||
|
bh = drw->fonts->h + 2;
|
||||||
|
lines = MAX(lines, 0);
|
||||||
|
mh = (lines + 1) * bh;
|
||||||
|
promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0;
|
||||||
|
#ifdef XINERAMA
|
||||||
|
i = 0;
|
||||||
|
if (parentwin == root && (info = XineramaQueryScreens(dpy, &n))) {
|
||||||
|
XGetInputFocus(dpy, &w, &di);
|
||||||
|
if (mon >= 0 && mon < n)
|
||||||
|
i = mon;
|
||||||
|
else if (w != root && w != PointerRoot && w != None) {
|
||||||
|
/* find top-level window containing current input focus */
|
||||||
|
do {
|
||||||
|
if (XQueryTree(dpy, (pw = w), &dw, &w, &dws, &du) && dws)
|
||||||
|
XFree(dws);
|
||||||
|
} while (w != root && w != pw);
|
||||||
|
/* find xinerama screen with which the window intersects most */
|
||||||
|
if (XGetWindowAttributes(dpy, pw, &wa))
|
||||||
|
for (j = 0; j < n; j++)
|
||||||
|
if ((a = INTERSECT(wa.x, wa.y, wa.width, wa.height, info[j])) > area) {
|
||||||
|
area = a;
|
||||||
|
i = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* no focused window is on screen, so use pointer location instead */
|
||||||
|
if (mon < 0 && !area && XQueryPointer(dpy, root, &dw, &dw, &x, &y, &di, &di, &du))
|
||||||
|
for (i = 0; i < n; i++)
|
||||||
|
if (INTERSECT(x, y, 1, 1, info[i]))
|
||||||
|
break;
|
||||||
|
|
||||||
|
mw = MIN(MAX(max_textw() + promptw, 100), info[i].width);
|
||||||
|
x = info[i].x_org + ((info[i].width - mw) / 2);
|
||||||
|
y = info[i].y_org + ((info[i].height - mh) / 2);
|
||||||
|
XFree(info);
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
if (!XGetWindowAttributes(dpy, parentwin, &wa))
|
||||||
|
die("could not get embedding window attributes: 0x%lx",
|
||||||
|
parentwin);
|
||||||
|
mw = MIN(MAX(max_textw() + promptw, 100), wa.width);
|
||||||
|
x = (wa.width - mw) / 2;
|
||||||
|
y = (wa.height - mh) / 2;
|
||||||
|
}
|
||||||
|
inputw = MIN(inputw, mw/3);
|
||||||
|
match();
|
||||||
|
|
||||||
|
/* create menu window */
|
||||||
|
swa.override_redirect = True;
|
||||||
|
swa.background_pixel = 0;
|
||||||
|
swa.border_pixel = 0;
|
||||||
|
swa.colormap = cmap;
|
||||||
|
swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask;
|
||||||
|
win = XCreateWindow(dpy, parentwin, x, y, mw, mh, border_width,
|
||||||
|
depth, CopyFromParent, visual,
|
||||||
|
CWOverrideRedirect | CWBackPixel | CWBorderPixel | CWColormap | CWEventMask, &swa);
|
||||||
|
XSetClassHint(dpy, win, &ch);
|
||||||
|
|
||||||
|
|
||||||
|
/* input methods */
|
||||||
|
if ((xim = XOpenIM(dpy, NULL, NULL, NULL)) == NULL)
|
||||||
|
die("XOpenIM failed: could not open input device");
|
||||||
|
|
||||||
|
xic = XCreateIC(xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
|
||||||
|
XNClientWindow, win, XNFocusWindow, win, NULL);
|
||||||
|
|
||||||
|
XMapRaised(dpy, win);
|
||||||
|
if (embed) {
|
||||||
|
XSelectInput(dpy, parentwin, FocusChangeMask | SubstructureNotifyMask);
|
||||||
|
if (XQueryTree(dpy, parentwin, &dw, &w, &dws, &du) && dws) {
|
||||||
|
for (i = 0; i < du && dws[i] != win; ++i)
|
||||||
|
XSelectInput(dpy, dws[i], FocusChangeMask);
|
||||||
|
XFree(dws);
|
||||||
|
}
|
||||||
|
grabfocus();
|
||||||
|
}
|
||||||
|
drw_resize(drw, mw, mh);
|
||||||
|
drawmenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
fputs("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n"
|
||||||
|
" [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n", stderr);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
XWindowAttributes wa;
|
||||||
|
int i, fast = 0;
|
||||||
|
|
||||||
|
for (i = 1; i < argc; i++)
|
||||||
|
/* these options take no arguments */
|
||||||
|
if (!strcmp(argv[i], "-v")) { /* prints version information */
|
||||||
|
puts("dmenu-"VERSION);
|
||||||
|
exit(0);
|
||||||
|
} else if (!strcmp(argv[i], "-b")) /* appears at the bottom of the screen */
|
||||||
|
topbar = 0;
|
||||||
|
else if (!strcmp(argv[i], "-f")) /* grabs keyboard before reading stdin */
|
||||||
|
fast = 1;
|
||||||
|
else if (!strcmp(argv[i], "-i")) { /* case-insensitive item matching */
|
||||||
|
fstrncmp = strncasecmp;
|
||||||
|
fstrstr = cistrstr;
|
||||||
|
} else if (i + 1 == argc)
|
||||||
|
usage();
|
||||||
|
/* these options take one argument */
|
||||||
|
else if (!strcmp(argv[i], "-g")) { /* number of columns in grid */
|
||||||
|
columns = atoi(argv[++i]);
|
||||||
|
if (lines == 0) lines = 1;
|
||||||
|
} else if (!strcmp(argv[i], "-l")) { /* number of lines in grid */
|
||||||
|
lines = atoi(argv[++i]);
|
||||||
|
if (columns == 0) columns = 1;
|
||||||
|
} else if (!strcmp(argv[i], "-m"))
|
||||||
|
mon = atoi(argv[++i]);
|
||||||
|
else if (!strcmp(argv[i], "-p")) /* adds prompt to left of input field */
|
||||||
|
prompt = argv[++i];
|
||||||
|
else if (!strcmp(argv[i], "-fn")) /* font or font set */
|
||||||
|
fonts[0] = argv[++i];
|
||||||
|
else if (!strcmp(argv[i], "-nb")) /* normal background color */
|
||||||
|
colors[SchemeNorm][ColBg] = argv[++i];
|
||||||
|
else if (!strcmp(argv[i], "-nf")) /* normal foreground color */
|
||||||
|
colors[SchemeNorm][ColFg] = argv[++i];
|
||||||
|
else if (!strcmp(argv[i], "-sb")) /* selected background color */
|
||||||
|
colors[SchemeSel][ColBg] = argv[++i];
|
||||||
|
else if (!strcmp(argv[i], "-sf")) /* selected foreground color */
|
||||||
|
colors[SchemeSel][ColFg] = argv[++i];
|
||||||
|
else if (!strcmp(argv[i], "-w")) /* embedding window id */
|
||||||
|
embed = argv[++i];
|
||||||
|
else
|
||||||
|
usage();
|
||||||
|
|
||||||
|
if (!setlocale(LC_CTYPE, "") || !XSupportsLocale())
|
||||||
|
fputs("warning: no locale support\n", stderr);
|
||||||
|
if (!(dpy = XOpenDisplay(NULL)))
|
||||||
|
die("cannot open display");
|
||||||
|
screen = DefaultScreen(dpy);
|
||||||
|
root = RootWindow(dpy, screen);
|
||||||
|
if (!embed || !(parentwin = strtol(embed, NULL, 0)))
|
||||||
|
parentwin = root;
|
||||||
|
if (!XGetWindowAttributes(dpy, parentwin, &wa))
|
||||||
|
die("could not get embedding window attributes: 0x%lx",
|
||||||
|
parentwin);
|
||||||
|
xinitvisual();
|
||||||
|
drw = drw_create(dpy, screen, root, wa.width, wa.height, visual, depth, cmap);
|
||||||
|
if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
|
||||||
|
die("no fonts could be loaded.");
|
||||||
|
lrpad = drw->fonts->h;
|
||||||
|
|
||||||
|
#ifdef __OpenBSD__
|
||||||
|
if (pledge("stdio rpath", NULL) == -1)
|
||||||
|
die("pledge");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (fast && !isatty(0)) {
|
||||||
|
grabkeyboard();
|
||||||
|
readstdin();
|
||||||
|
} else {
|
||||||
|
readstdin();
|
||||||
|
grabkeyboard();
|
||||||
|
}
|
||||||
|
setup();
|
||||||
|
run();
|
||||||
|
|
||||||
|
return 1; /* unreachable */
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
xinitvisual()
|
||||||
|
{
|
||||||
|
XVisualInfo *infos;
|
||||||
|
XRenderPictFormat *fmt;
|
||||||
|
int nitems;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
XVisualInfo tpl = {
|
||||||
|
.screen = screen,
|
||||||
|
.depth = 32,
|
||||||
|
.class = TrueColor
|
||||||
|
};
|
||||||
|
long masks = VisualScreenMask | VisualDepthMask | VisualClassMask;
|
||||||
|
|
||||||
|
infos = XGetVisualInfo(dpy, masks, &tpl, &nitems);
|
||||||
|
visual = NULL;
|
||||||
|
for(i = 0; i < nitems; i ++) {
|
||||||
|
fmt = XRenderFindVisualFormat(dpy, infos[i].visual);
|
||||||
|
if (fmt->type == PictTypeDirect && fmt->direct.alphaMask) {
|
||||||
|
visual = infos[i].visual;
|
||||||
|
depth = infos[i].depth;
|
||||||
|
cmap = XCreateColormap(dpy, root, visual, AllocNone);
|
||||||
|
useargb = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
XFree(infos);
|
||||||
|
|
||||||
|
if (! visual) {
|
||||||
|
visual = DefaultVisual(dpy, screen);
|
||||||
|
depth = DefaultDepth(dpy, screen);
|
||||||
|
cmap = DefaultColormap(dpy, screen);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,850 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <locale.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <strings.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include <X11/Xatom.h>
|
||||||
|
#include <X11/Xproto.h>
|
||||||
|
#include <X11/Xutil.h>
|
||||||
|
#ifdef XINERAMA
|
||||||
|
#include <X11/extensions/Xinerama.h>
|
||||||
|
#endif
|
||||||
|
#include <X11/Xft/Xft.h>
|
||||||
|
|
||||||
|
#include "drw.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
/* macros */
|
||||||
|
#define INTERSECT(x,y,w,h,r) (MAX(0, MIN((x)+(w),(r).x_org+(r).width) - MAX((x),(r).x_org)) \
|
||||||
|
* MAX(0, MIN((y)+(h),(r).y_org+(r).height) - MAX((y),(r).y_org)))
|
||||||
|
#define LENGTH(X) (sizeof X / sizeof X[0])
|
||||||
|
#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
|
||||||
|
|
||||||
|
#define OPAQUE 0xffU
|
||||||
|
|
||||||
|
/* enums */
|
||||||
|
enum { SchemeNorm, SchemeSel, SchemeOut, SchemeLast }; /* color schemes */
|
||||||
|
|
||||||
|
struct item {
|
||||||
|
char *text;
|
||||||
|
struct item *left, *right;
|
||||||
|
int out;
|
||||||
|
};
|
||||||
|
|
||||||
|
static char text[BUFSIZ] = "";
|
||||||
|
static char *embed;
|
||||||
|
static int bh, mw, mh;
|
||||||
|
static int inputw = 0, promptw;
|
||||||
|
static int lrpad; /* sum of left and right padding */
|
||||||
|
static size_t cursor;
|
||||||
|
static struct item *items = NULL;
|
||||||
|
static struct item *matches, *matchend;
|
||||||
|
static struct item *prev, *curr, *next, *sel;
|
||||||
|
static int mon = -1, screen;
|
||||||
|
|
||||||
|
static Atom clip, utf8;
|
||||||
|
static Display *dpy;
|
||||||
|
static Window root, parentwin, win;
|
||||||
|
static XIC xic;
|
||||||
|
|
||||||
|
static Drw *drw;
|
||||||
|
static Clr *scheme[SchemeLast];
|
||||||
|
|
||||||
|
static int useargb = 0;
|
||||||
|
static Visual *visual;
|
||||||
|
static int depth;
|
||||||
|
static Colormap cmap;
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
static int (*fstrncmp)(const char *, const char *, size_t) = strncmp;
|
||||||
|
static char *(*fstrstr)(const char *, const char *) = strstr;
|
||||||
|
static void xinitvisual();
|
||||||
|
|
||||||
|
static void
|
||||||
|
appenditem(struct item *item, struct item **list, struct item **last)
|
||||||
|
{
|
||||||
|
if (*last)
|
||||||
|
(*last)->right = item;
|
||||||
|
else
|
||||||
|
*list = item;
|
||||||
|
|
||||||
|
item->left = *last;
|
||||||
|
item->right = NULL;
|
||||||
|
*last = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
calcoffsets(void)
|
||||||
|
{
|
||||||
|
int i, n;
|
||||||
|
|
||||||
|
if (lines > 0)
|
||||||
|
n = lines * columns * bh;
|
||||||
|
else
|
||||||
|
n = mw - (promptw + inputw + TEXTW("<") + TEXTW(">"));
|
||||||
|
/* calculate which items will begin the next page and previous page */
|
||||||
|
for (i = 0, next = curr; next; next = next->right)
|
||||||
|
if ((i += (lines > 0) ? bh : MIN(TEXTW(next->text), n)) > n)
|
||||||
|
break;
|
||||||
|
for (i = 0, prev = curr; prev && prev->left; prev = prev->left)
|
||||||
|
if ((i += (lines > 0) ? bh : MIN(TEXTW(prev->left->text), n)) > n)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
max_textw(void)
|
||||||
|
{
|
||||||
|
int len = 0;
|
||||||
|
for (struct item *item = items; item && item->text; item++)
|
||||||
|
len = MAX(TEXTW(item->text), len);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cleanup(void)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
XUngrabKey(dpy, AnyKey, AnyModifier, root);
|
||||||
|
for (i = 0; i < SchemeLast; i++)
|
||||||
|
free(scheme[i]);
|
||||||
|
drw_free(drw);
|
||||||
|
XSync(dpy, False);
|
||||||
|
XCloseDisplay(dpy);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *
|
||||||
|
cistrstr(const char *s, const char *sub)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
for (len = strlen(sub); *s; s++)
|
||||||
|
if (!strncasecmp(s, sub, len))
|
||||||
|
return (char *)s;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
drawitem(struct item *item, int x, int y, int w)
|
||||||
|
{
|
||||||
|
if (item == sel)
|
||||||
|
drw_setscheme(drw, scheme[SchemeSel]);
|
||||||
|
else if (item->out)
|
||||||
|
drw_setscheme(drw, scheme[SchemeOut]);
|
||||||
|
else
|
||||||
|
drw_setscheme(drw, scheme[SchemeNorm]);
|
||||||
|
|
||||||
|
return drw_text(drw, x, y, w, bh, lrpad / 2, item->text, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
drawmenu(void)
|
||||||
|
{
|
||||||
|
unsigned int curpos;
|
||||||
|
struct item *item;
|
||||||
|
int x = 0, y = 0, w;
|
||||||
|
|
||||||
|
drw_setscheme(drw, scheme[SchemeNorm]);
|
||||||
|
drw_rect(drw, 0, 0, mw, mh, 1, 1);
|
||||||
|
|
||||||
|
if (prompt && *prompt) {
|
||||||
|
drw_setscheme(drw, scheme[SchemeSel]);
|
||||||
|
x = drw_text(drw, x, 0, promptw, bh, lrpad / 2, prompt, 0);
|
||||||
|
}
|
||||||
|
/* draw input field */
|
||||||
|
w = (lines > 0 || !matches) ? mw - x : inputw;
|
||||||
|
drw_setscheme(drw, scheme[SchemeNorm]);
|
||||||
|
drw_text(drw, x, 0, w, bh, lrpad / 2, text, 0);
|
||||||
|
|
||||||
|
curpos = TEXTW(text) - TEXTW(&text[cursor]);
|
||||||
|
if ((curpos += lrpad / 2 - 1) < w) {
|
||||||
|
drw_setscheme(drw, scheme[SchemeNorm]);
|
||||||
|
drw_rect(drw, x + curpos, 2, 2, bh - 4, 1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lines > 0) {
|
||||||
|
/* draw grid */
|
||||||
|
int i = 0;
|
||||||
|
for (item = curr; item != next; item = item->right, i++)
|
||||||
|
drawitem(
|
||||||
|
item,
|
||||||
|
x + ((i / lines) * ((mw - x) / columns)),
|
||||||
|
y + (((i % lines) + 1) * bh),
|
||||||
|
(mw - x) / columns
|
||||||
|
);
|
||||||
|
} else if (matches) {
|
||||||
|
/* draw horizontal list */
|
||||||
|
x += inputw;
|
||||||
|
w = TEXTW("<");
|
||||||
|
if (curr->left) {
|
||||||
|
drw_setscheme(drw, scheme[SchemeNorm]);
|
||||||
|
drw_text(drw, x, 0, w, bh, lrpad / 2, "<", 0);
|
||||||
|
}
|
||||||
|
x += w;
|
||||||
|
for (item = curr; item != next; item = item->right)
|
||||||
|
x = drawitem(item, x, 0, MIN(TEXTW(item->text), mw - x - TEXTW(">")));
|
||||||
|
if (next) {
|
||||||
|
w = TEXTW(">");
|
||||||
|
drw_setscheme(drw, scheme[SchemeNorm]);
|
||||||
|
drw_text(drw, mw - w, 0, w, bh, lrpad / 2, ">", 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
drw_map(drw, win, 0, 0, mw, mh);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
grabfocus(void)
|
||||||
|
{
|
||||||
|
struct timespec ts = { .tv_sec = 0, .tv_nsec = 10000000 };
|
||||||
|
Window focuswin;
|
||||||
|
int i, revertwin;
|
||||||
|
|
||||||
|
for (i = 0; i < 100; ++i) {
|
||||||
|
XGetInputFocus(dpy, &focuswin, &revertwin);
|
||||||
|
if (focuswin == win)
|
||||||
|
return;
|
||||||
|
XSetInputFocus(dpy, win, RevertToParent, CurrentTime);
|
||||||
|
nanosleep(&ts, NULL);
|
||||||
|
}
|
||||||
|
die("cannot grab focus");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
grabkeyboard(void)
|
||||||
|
{
|
||||||
|
struct timespec ts = { .tv_sec = 0, .tv_nsec = 1000000 };
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (embed)
|
||||||
|
return;
|
||||||
|
/* try to grab keyboard, we may have to wait for another process to ungrab */
|
||||||
|
for (i = 0; i < 1000; i++) {
|
||||||
|
if (XGrabKeyboard(dpy, DefaultRootWindow(dpy), True, GrabModeAsync,
|
||||||
|
GrabModeAsync, CurrentTime) == GrabSuccess)
|
||||||
|
return;
|
||||||
|
nanosleep(&ts, NULL);
|
||||||
|
}
|
||||||
|
die("cannot grab keyboard");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
match(void)
|
||||||
|
{
|
||||||
|
static char **tokv = NULL;
|
||||||
|
static int tokn = 0;
|
||||||
|
|
||||||
|
char buf[sizeof text], *s;
|
||||||
|
int i, tokc = 0;
|
||||||
|
size_t len, textsize;
|
||||||
|
struct item *item, *lprefix, *lsubstr, *prefixend, *substrend;
|
||||||
|
|
||||||
|
strcpy(buf, text);
|
||||||
|
/* separate input text into tokens to be matched individually */
|
||||||
|
for (s = strtok(buf, " "); s; tokv[tokc - 1] = s, s = strtok(NULL, " "))
|
||||||
|
if (++tokc > tokn && !(tokv = realloc(tokv, ++tokn * sizeof *tokv)))
|
||||||
|
die("cannot realloc %u bytes:", tokn * sizeof *tokv);
|
||||||
|
len = tokc ? strlen(tokv[0]) : 0;
|
||||||
|
|
||||||
|
matches = lprefix = lsubstr = matchend = prefixend = substrend = NULL;
|
||||||
|
textsize = strlen(text) + 1;
|
||||||
|
for (item = items; item && item->text; item++) {
|
||||||
|
for (i = 0; i < tokc; i++)
|
||||||
|
if (!fstrstr(item->text, tokv[i]))
|
||||||
|
break;
|
||||||
|
if (i != tokc) /* not all tokens match */
|
||||||
|
continue;
|
||||||
|
/* exact matches go first, then prefixes, then substrings */
|
||||||
|
if (!tokc || !fstrncmp(text, item->text, textsize))
|
||||||
|
appenditem(item, &matches, &matchend);
|
||||||
|
else if (!fstrncmp(tokv[0], item->text, len))
|
||||||
|
appenditem(item, &lprefix, &prefixend);
|
||||||
|
else
|
||||||
|
appenditem(item, &lsubstr, &substrend);
|
||||||
|
}
|
||||||
|
if (lprefix) {
|
||||||
|
if (matches) {
|
||||||
|
matchend->right = lprefix;
|
||||||
|
lprefix->left = matchend;
|
||||||
|
} else
|
||||||
|
matches = lprefix;
|
||||||
|
matchend = prefixend;
|
||||||
|
}
|
||||||
|
if (lsubstr) {
|
||||||
|
if (matches) {
|
||||||
|
matchend->right = lsubstr;
|
||||||
|
lsubstr->left = matchend;
|
||||||
|
} else
|
||||||
|
matches = lsubstr;
|
||||||
|
matchend = substrend;
|
||||||
|
}
|
||||||
|
curr = sel = matches;
|
||||||
|
calcoffsets();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
insert(const char *str, ssize_t n)
|
||||||
|
{
|
||||||
|
if (strlen(text) + n > sizeof text - 1)
|
||||||
|
return;
|
||||||
|
/* move existing text out of the way, insert new text, and update cursor */
|
||||||
|
memmove(&text[cursor + n], &text[cursor], sizeof text - cursor - MAX(n, 0));
|
||||||
|
if (n > 0)
|
||||||
|
memcpy(&text[cursor], str, n);
|
||||||
|
cursor += n;
|
||||||
|
match();
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
nextrune(int inc)
|
||||||
|
{
|
||||||
|
ssize_t n;
|
||||||
|
|
||||||
|
/* return location of next utf8 rune in the given direction (+1 or -1) */
|
||||||
|
for (n = cursor + inc; n + inc >= 0 && (text[n] & 0xc0) == 0x80; n += inc)
|
||||||
|
;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
movewordedge(int dir)
|
||||||
|
{
|
||||||
|
if (dir < 0) { /* move cursor to the start of the word*/
|
||||||
|
while (cursor > 0 && strchr(worddelimiters, text[nextrune(-1)]))
|
||||||
|
cursor = nextrune(-1);
|
||||||
|
while (cursor > 0 && !strchr(worddelimiters, text[nextrune(-1)]))
|
||||||
|
cursor = nextrune(-1);
|
||||||
|
} else { /* move cursor to the end of the word */
|
||||||
|
while (text[cursor] && strchr(worddelimiters, text[cursor]))
|
||||||
|
cursor = nextrune(+1);
|
||||||
|
while (text[cursor] && !strchr(worddelimiters, text[cursor]))
|
||||||
|
cursor = nextrune(+1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
keypress(XKeyEvent *ev)
|
||||||
|
{
|
||||||
|
char buf[32];
|
||||||
|
int len;
|
||||||
|
KeySym ksym;
|
||||||
|
Status status;
|
||||||
|
|
||||||
|
len = XmbLookupString(xic, ev, buf, sizeof buf, &ksym, &status);
|
||||||
|
switch (status) {
|
||||||
|
default: /* XLookupNone, XBufferOverflow */
|
||||||
|
return;
|
||||||
|
case XLookupChars:
|
||||||
|
goto insert;
|
||||||
|
case XLookupKeySym:
|
||||||
|
case XLookupBoth:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ev->state & ControlMask) {
|
||||||
|
switch(ksym) {
|
||||||
|
case XK_a: ksym = XK_Home; break;
|
||||||
|
case XK_b: ksym = XK_Left; break;
|
||||||
|
case XK_c: ksym = XK_Escape; break;
|
||||||
|
case XK_d: ksym = XK_Delete; break;
|
||||||
|
case XK_e: ksym = XK_End; break;
|
||||||
|
case XK_f: ksym = XK_Right; break;
|
||||||
|
case XK_g: ksym = XK_Escape; break;
|
||||||
|
case XK_h: ksym = XK_BackSpace; break;
|
||||||
|
case XK_i: ksym = XK_Tab; break;
|
||||||
|
case XK_j: /* fallthrough */
|
||||||
|
case XK_J: /* fallthrough */
|
||||||
|
case XK_m: /* fallthrough */
|
||||||
|
case XK_M: ksym = XK_Return; ev->state &= ~ControlMask; break;
|
||||||
|
case XK_n: ksym = XK_Down; break;
|
||||||
|
case XK_p: ksym = XK_Up; break;
|
||||||
|
|
||||||
|
case XK_k: /* delete right */
|
||||||
|
text[cursor] = '\0';
|
||||||
|
match();
|
||||||
|
break;
|
||||||
|
case XK_u: /* delete left */
|
||||||
|
insert(NULL, 0 - cursor);
|
||||||
|
break;
|
||||||
|
case XK_w: /* delete word */
|
||||||
|
while (cursor > 0 && strchr(worddelimiters, text[nextrune(-1)]))
|
||||||
|
insert(NULL, nextrune(-1) - cursor);
|
||||||
|
while (cursor > 0 && !strchr(worddelimiters, text[nextrune(-1)]))
|
||||||
|
insert(NULL, nextrune(-1) - cursor);
|
||||||
|
break;
|
||||||
|
case XK_y: /* paste selection */
|
||||||
|
case XK_Y:
|
||||||
|
XConvertSelection(dpy, (ev->state & ShiftMask) ? clip : XA_PRIMARY,
|
||||||
|
utf8, utf8, win, CurrentTime);
|
||||||
|
return;
|
||||||
|
case XK_Left:
|
||||||
|
case XK_KP_Left:
|
||||||
|
movewordedge(-1);
|
||||||
|
goto draw;
|
||||||
|
case XK_Right:
|
||||||
|
case XK_KP_Right:
|
||||||
|
movewordedge(+1);
|
||||||
|
goto draw;
|
||||||
|
case XK_Return:
|
||||||
|
case XK_KP_Enter:
|
||||||
|
break;
|
||||||
|
case XK_bracketleft:
|
||||||
|
cleanup();
|
||||||
|
exit(1);
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else if (ev->state & Mod1Mask) {
|
||||||
|
switch(ksym) {
|
||||||
|
case XK_b:
|
||||||
|
movewordedge(-1);
|
||||||
|
goto draw;
|
||||||
|
case XK_f:
|
||||||
|
movewordedge(+1);
|
||||||
|
goto draw;
|
||||||
|
case XK_g: ksym = XK_Home; break;
|
||||||
|
case XK_G: ksym = XK_End; break;
|
||||||
|
case XK_h: ksym = XK_Up; break;
|
||||||
|
case XK_j: ksym = XK_Next; break;
|
||||||
|
case XK_k: ksym = XK_Prior; break;
|
||||||
|
case XK_l: ksym = XK_Down; break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(ksym) {
|
||||||
|
default:
|
||||||
|
insert:
|
||||||
|
if (!iscntrl(*buf))
|
||||||
|
insert(buf, len);
|
||||||
|
break;
|
||||||
|
case XK_Delete:
|
||||||
|
case XK_KP_Delete:
|
||||||
|
if (text[cursor] == '\0')
|
||||||
|
return;
|
||||||
|
cursor = nextrune(+1);
|
||||||
|
/* fallthrough */
|
||||||
|
case XK_BackSpace:
|
||||||
|
if (cursor == 0)
|
||||||
|
return;
|
||||||
|
insert(NULL, nextrune(-1) - cursor);
|
||||||
|
break;
|
||||||
|
case XK_End:
|
||||||
|
case XK_KP_End:
|
||||||
|
if (text[cursor] != '\0') {
|
||||||
|
cursor = strlen(text);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (next) {
|
||||||
|
/* jump to end of list and position items in reverse */
|
||||||
|
curr = matchend;
|
||||||
|
calcoffsets();
|
||||||
|
curr = prev;
|
||||||
|
calcoffsets();
|
||||||
|
while (next && (curr = curr->right))
|
||||||
|
calcoffsets();
|
||||||
|
}
|
||||||
|
sel = matchend;
|
||||||
|
break;
|
||||||
|
case XK_Escape:
|
||||||
|
cleanup();
|
||||||
|
exit(1);
|
||||||
|
case XK_Home:
|
||||||
|
case XK_KP_Home:
|
||||||
|
if (sel == matches) {
|
||||||
|
cursor = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sel = curr = matches;
|
||||||
|
calcoffsets();
|
||||||
|
break;
|
||||||
|
case XK_Left:
|
||||||
|
case XK_KP_Left:
|
||||||
|
if (cursor > 0 && (!sel || !sel->left || lines > 0)) {
|
||||||
|
cursor = nextrune(-1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (lines > 0)
|
||||||
|
return;
|
||||||
|
/* fallthrough */
|
||||||
|
case XK_Up:
|
||||||
|
case XK_KP_Up:
|
||||||
|
if (sel && sel->left && (sel = sel->left)->right == curr) {
|
||||||
|
curr = prev;
|
||||||
|
calcoffsets();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case XK_Next:
|
||||||
|
case XK_KP_Next:
|
||||||
|
if (!next)
|
||||||
|
return;
|
||||||
|
sel = curr = next;
|
||||||
|
calcoffsets();
|
||||||
|
break;
|
||||||
|
case XK_Prior:
|
||||||
|
case XK_KP_Prior:
|
||||||
|
if (!prev)
|
||||||
|
return;
|
||||||
|
sel = curr = prev;
|
||||||
|
calcoffsets();
|
||||||
|
break;
|
||||||
|
case XK_Return:
|
||||||
|
case XK_KP_Enter:
|
||||||
|
puts((sel && !(ev->state & ShiftMask)) ? sel->text : text);
|
||||||
|
if (!(ev->state & ControlMask)) {
|
||||||
|
cleanup();
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
if (sel)
|
||||||
|
sel->out = 1;
|
||||||
|
break;
|
||||||
|
case XK_Right:
|
||||||
|
case XK_KP_Right:
|
||||||
|
if (text[cursor] != '\0') {
|
||||||
|
cursor = nextrune(+1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (lines > 0)
|
||||||
|
return;
|
||||||
|
/* fallthrough */
|
||||||
|
case XK_Down:
|
||||||
|
case XK_KP_Down:
|
||||||
|
if (sel && sel->right && (sel = sel->right) == next) {
|
||||||
|
curr = next;
|
||||||
|
calcoffsets();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case XK_Tab:
|
||||||
|
if (!sel)
|
||||||
|
return;
|
||||||
|
strncpy(text, sel->text, sizeof text - 1);
|
||||||
|
text[sizeof text - 1] = '\0';
|
||||||
|
cursor = strlen(text);
|
||||||
|
match();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
draw:
|
||||||
|
drawmenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
paste(void)
|
||||||
|
{
|
||||||
|
char *p, *q;
|
||||||
|
int di;
|
||||||
|
unsigned long dl;
|
||||||
|
Atom da;
|
||||||
|
|
||||||
|
/* we have been given the current selection, now insert it into input */
|
||||||
|
if (XGetWindowProperty(dpy, win, utf8, 0, (sizeof text / 4) + 1, False,
|
||||||
|
utf8, &da, &di, &dl, &dl, (unsigned char **)&p)
|
||||||
|
== Success && p) {
|
||||||
|
insert(p, (q = strchr(p, '\n')) ? q - p : (ssize_t)strlen(p));
|
||||||
|
XFree(p);
|
||||||
|
}
|
||||||
|
drawmenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
readstdin(void)
|
||||||
|
{
|
||||||
|
char buf[sizeof text], *p;
|
||||||
|
size_t i, imax = 0, size = 0;
|
||||||
|
unsigned int tmpmax = 0;
|
||||||
|
|
||||||
|
/* read each line from stdin and add it to the item list */
|
||||||
|
for (i = 0; fgets(buf, sizeof buf, stdin); i++) {
|
||||||
|
if (i + 1 >= size / sizeof *items)
|
||||||
|
if (!(items = realloc(items, (size += BUFSIZ))))
|
||||||
|
die("cannot realloc %u bytes:", size);
|
||||||
|
if ((p = strchr(buf, '\n')))
|
||||||
|
*p = '\0';
|
||||||
|
if (!(items[i].text = strdup(buf)))
|
||||||
|
die("cannot strdup %u bytes:", strlen(buf) + 1);
|
||||||
|
items[i].out = 0;
|
||||||
|
drw_font_getexts(drw->fonts, buf, strlen(buf), &tmpmax, NULL);
|
||||||
|
if (tmpmax > inputw) {
|
||||||
|
inputw = tmpmax;
|
||||||
|
imax = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (items)
|
||||||
|
items[i].text = NULL;
|
||||||
|
inputw = items ? TEXTW(items[imax].text) : 0;
|
||||||
|
lines = MIN(lines, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
run(void)
|
||||||
|
{
|
||||||
|
XEvent ev;
|
||||||
|
|
||||||
|
while (!XNextEvent(dpy, &ev)) {
|
||||||
|
if (XFilterEvent(&ev, win))
|
||||||
|
continue;
|
||||||
|
switch(ev.type) {
|
||||||
|
case DestroyNotify:
|
||||||
|
if (ev.xdestroywindow.window != win)
|
||||||
|
break;
|
||||||
|
cleanup();
|
||||||
|
exit(1);
|
||||||
|
case Expose:
|
||||||
|
if (ev.xexpose.count == 0)
|
||||||
|
drw_map(drw, win, 0, 0, mw, mh);
|
||||||
|
break;
|
||||||
|
case FocusIn:
|
||||||
|
/* regrab focus from parent window */
|
||||||
|
if (ev.xfocus.window != win)
|
||||||
|
grabfocus();
|
||||||
|
break;
|
||||||
|
case KeyPress:
|
||||||
|
keypress(&ev.xkey);
|
||||||
|
break;
|
||||||
|
case SelectionNotify:
|
||||||
|
if (ev.xselection.property == utf8)
|
||||||
|
paste();
|
||||||
|
break;
|
||||||
|
case VisibilityNotify:
|
||||||
|
if (ev.xvisibility.state != VisibilityUnobscured)
|
||||||
|
XRaiseWindow(dpy, win);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
setup(void)
|
||||||
|
{
|
||||||
|
int x, y, i, j;
|
||||||
|
unsigned int du;
|
||||||
|
XSetWindowAttributes swa;
|
||||||
|
XIM xim;
|
||||||
|
Window w, dw, *dws;
|
||||||
|
XWindowAttributes wa;
|
||||||
|
XClassHint ch = {"dmenu", "dmenu"};
|
||||||
|
#ifdef XINERAMA
|
||||||
|
XineramaScreenInfo *info;
|
||||||
|
Window pw;
|
||||||
|
int a, di, n, area = 0;
|
||||||
|
#endif
|
||||||
|
/* init appearance */
|
||||||
|
for (j = 0; j < SchemeLast; j++)
|
||||||
|
scheme[j] = drw_scm_create(drw, colors[j], alphas[i], 2);
|
||||||
|
|
||||||
|
clip = XInternAtom(dpy, "CLIPBOARD", False);
|
||||||
|
utf8 = XInternAtom(dpy, "UTF8_STRING", False);
|
||||||
|
|
||||||
|
/* calculate menu geometry */
|
||||||
|
bh = drw->fonts->h + 2;
|
||||||
|
lines = MAX(lines, 0);
|
||||||
|
mh = (lines + 1) * bh;
|
||||||
|
promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0;
|
||||||
|
#ifdef XINERAMA
|
||||||
|
i = 0;
|
||||||
|
if (parentwin == root && (info = XineramaQueryScreens(dpy, &n))) {
|
||||||
|
XGetInputFocus(dpy, &w, &di);
|
||||||
|
if (mon >= 0 && mon < n)
|
||||||
|
i = mon;
|
||||||
|
else if (w != root && w != PointerRoot && w != None) {
|
||||||
|
/* find top-level window containing current input focus */
|
||||||
|
do {
|
||||||
|
if (XQueryTree(dpy, (pw = w), &dw, &w, &dws, &du) && dws)
|
||||||
|
XFree(dws);
|
||||||
|
} while (w != root && w != pw);
|
||||||
|
/* find xinerama screen with which the window intersects most */
|
||||||
|
if (XGetWindowAttributes(dpy, pw, &wa))
|
||||||
|
for (j = 0; j < n; j++)
|
||||||
|
if ((a = INTERSECT(wa.x, wa.y, wa.width, wa.height, info[j])) > area) {
|
||||||
|
area = a;
|
||||||
|
i = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* no focused window is on screen, so use pointer location instead */
|
||||||
|
if (mon < 0 && !area && XQueryPointer(dpy, root, &dw, &dw, &x, &y, &di, &di, &du))
|
||||||
|
for (i = 0; i < n; i++)
|
||||||
|
if (INTERSECT(x, y, 1, 1, info[i]))
|
||||||
|
break;
|
||||||
|
|
||||||
|
mw = MIN(MAX(max_textw() + promptw, 100), info[i].width);
|
||||||
|
x = info[i].x_org + ((info[i].width - mw) / 2);
|
||||||
|
y = info[i].y_org + ((info[i].height - mh) / 2);
|
||||||
|
XFree(info);
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
if (!XGetWindowAttributes(dpy, parentwin, &wa))
|
||||||
|
die("could not get embedding window attributes: 0x%lx",
|
||||||
|
parentwin);
|
||||||
|
mw = MIN(MAX(max_textw() + promptw, 100), wa.width);
|
||||||
|
x = (wa.width - mw) / 2;
|
||||||
|
y = (wa.height - mh) / 2;
|
||||||
|
}
|
||||||
|
inputw = MIN(inputw, mw/3);
|
||||||
|
match();
|
||||||
|
|
||||||
|
/* create menu window */
|
||||||
|
swa.override_redirect = True;
|
||||||
|
swa.background_pixel = 0;
|
||||||
|
swa.border_pixel = 0;
|
||||||
|
swa.colormap = cmap;
|
||||||
|
swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask;
|
||||||
|
win = XCreateWindow(dpy, parentwin, x, y, mw, mh, border_width,
|
||||||
|
depth, CopyFromParent, visual,
|
||||||
|
CWOverrideRedirect | CWBackPixel | CWBorderPixel | CWColormap | CWEventMask, &swa);
|
||||||
|
XSetClassHint(dpy, win, &ch);
|
||||||
|
|
||||||
|
|
||||||
|
/* input methods */
|
||||||
|
if ((xim = XOpenIM(dpy, NULL, NULL, NULL)) == NULL)
|
||||||
|
die("XOpenIM failed: could not open input device");
|
||||||
|
|
||||||
|
xic = XCreateIC(xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
|
||||||
|
XNClientWindow, win, XNFocusWindow, win, NULL);
|
||||||
|
|
||||||
|
XMapRaised(dpy, win);
|
||||||
|
if (embed) {
|
||||||
|
XSelectInput(dpy, parentwin, FocusChangeMask | SubstructureNotifyMask);
|
||||||
|
if (XQueryTree(dpy, parentwin, &dw, &w, &dws, &du) && dws) {
|
||||||
|
for (i = 0; i < du && dws[i] != win; ++i)
|
||||||
|
XSelectInput(dpy, dws[i], FocusChangeMask);
|
||||||
|
XFree(dws);
|
||||||
|
}
|
||||||
|
grabfocus();
|
||||||
|
}
|
||||||
|
drw_resize(drw, mw, mh);
|
||||||
|
drawmenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
fputs("usage: dmenu [-bfiv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n"
|
||||||
|
" [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n", stderr);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
XWindowAttributes wa;
|
||||||
|
int i, fast = 0;
|
||||||
|
|
||||||
|
for (i = 1; i < argc; i++)
|
||||||
|
/* these options take no arguments */
|
||||||
|
if (!strcmp(argv[i], "-v")) { /* prints version information */
|
||||||
|
puts("dmenu-"VERSION);
|
||||||
|
exit(0);
|
||||||
|
} else if (!strcmp(argv[i], "-b")) /* appears at the bottom of the screen */
|
||||||
|
topbar = 0;
|
||||||
|
else if (!strcmp(argv[i], "-f")) /* grabs keyboard before reading stdin */
|
||||||
|
fast = 1;
|
||||||
|
else if (!strcmp(argv[i], "-i")) { /* case-insensitive item matching */
|
||||||
|
fstrncmp = strncasecmp;
|
||||||
|
fstrstr = cistrstr;
|
||||||
|
} else if (i + 1 == argc)
|
||||||
|
usage();
|
||||||
|
/* these options take one argument */
|
||||||
|
else if (!strcmp(argv[i], "-g")) { /* number of columns in grid */
|
||||||
|
columns = atoi(argv[++i]);
|
||||||
|
if (lines == 0) lines = 1;
|
||||||
|
} else if (!strcmp(argv[i], "-l")) { /* number of lines in grid */
|
||||||
|
lines = atoi(argv[++i]);
|
||||||
|
if (columns == 0) columns = 1;
|
||||||
|
} else if (!strcmp(argv[i], "-m"))
|
||||||
|
mon = atoi(argv[++i]);
|
||||||
|
else if (!strcmp(argv[i], "-p")) /* adds prompt to left of input field */
|
||||||
|
prompt = argv[++i];
|
||||||
|
else if (!strcmp(argv[i], "-fn")) /* font or font set */
|
||||||
|
fonts[0] = argv[++i];
|
||||||
|
else if (!strcmp(argv[i], "-nb")) /* normal background color */
|
||||||
|
colors[SchemeNorm][ColBg] = argv[++i];
|
||||||
|
else if (!strcmp(argv[i], "-nf")) /* normal foreground color */
|
||||||
|
colors[SchemeNorm][ColFg] = argv[++i];
|
||||||
|
else if (!strcmp(argv[i], "-sb")) /* selected background color */
|
||||||
|
colors[SchemeSel][ColBg] = argv[++i];
|
||||||
|
else if (!strcmp(argv[i], "-sf")) /* selected foreground color */
|
||||||
|
colors[SchemeSel][ColFg] = argv[++i];
|
||||||
|
else if (!strcmp(argv[i], "-w")) /* embedding window id */
|
||||||
|
embed = argv[++i];
|
||||||
|
else
|
||||||
|
usage();
|
||||||
|
|
||||||
|
if (!setlocale(LC_CTYPE, "") || !XSupportsLocale())
|
||||||
|
fputs("warning: no locale support\n", stderr);
|
||||||
|
if (!(dpy = XOpenDisplay(NULL)))
|
||||||
|
die("cannot open display");
|
||||||
|
screen = DefaultScreen(dpy);
|
||||||
|
root = RootWindow(dpy, screen);
|
||||||
|
if (!embed || !(parentwin = strtol(embed, NULL, 0)))
|
||||||
|
parentwin = root;
|
||||||
|
if (!XGetWindowAttributes(dpy, parentwin, &wa))
|
||||||
|
die("could not get embedding window attributes: 0x%lx",
|
||||||
|
parentwin);
|
||||||
|
xinitvisual();
|
||||||
|
drw = drw_create(dpy, screen, root, wa.width, wa.height, visual, depth, cmap);
|
||||||
|
if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
|
||||||
|
die("no fonts could be loaded.");
|
||||||
|
lrpad = drw->fonts->h;
|
||||||
|
|
||||||
|
#ifdef __OpenBSD__
|
||||||
|
if (pledge("stdio rpath", NULL) == -1)
|
||||||
|
die("pledge");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (fast && !isatty(0)) {
|
||||||
|
grabkeyboard();
|
||||||
|
readstdin();
|
||||||
|
} else {
|
||||||
|
readstdin();
|
||||||
|
grabkeyboard();
|
||||||
|
}
|
||||||
|
setup();
|
||||||
|
run();
|
||||||
|
|
||||||
|
return 1; /* unreachable */
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
xinitvisual()
|
||||||
|
{
|
||||||
|
XVisualInfo *infos;
|
||||||
|
XRenderPictFormat *fmt;
|
||||||
|
int nitems;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
XVisualInfo tpl = {
|
||||||
|
.screen = screen,
|
||||||
|
.depth = 32,
|
||||||
|
.class = TrueColor
|
||||||
|
};
|
||||||
|
long masks = VisualScreenMask | VisualDepthMask | VisualClassMask;
|
||||||
|
|
||||||
|
infos = XGetVisualInfo(dpy, masks, &tpl, &nitems);
|
||||||
|
visual = NULL;
|
||||||
|
for(i = 0; i < nitems; i ++) {
|
||||||
|
fmt = XRenderFindVisualFormat(dpy, infos[i].visual);
|
||||||
|
if (fmt->type == PictTypeDirect && fmt->direct.alphaMask) {
|
||||||
|
visual = infos[i].visual;
|
||||||
|
depth = infos[i].depth;
|
||||||
|
cmap = XCreateColormap(dpy, root, visual, AllocNone);
|
||||||
|
useargb = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
XFree(infos);
|
||||||
|
|
||||||
|
if (! visual) {
|
||||||
|
visual = DefaultVisual(dpy, screen);
|
||||||
|
depth = DefaultDepth(dpy, screen);
|
||||||
|
cmap = DefaultColormap(dpy, screen);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
--- dmenu.c 2019-02-02 13:55:02.000000000 +0100
|
||||||
|
+++ dmenu.c 2019-05-19 02:11:20.966710117 +0200
|
||||||
|
@@ -654,9 +654,10 @@ setup(void)
|
||||||
|
swa.override_redirect = True;
|
||||||
|
swa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
|
||||||
|
swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask;
|
||||||
|
- win = XCreateWindow(dpy, parentwin, x, y, mw, mh, 0,
|
||||||
|
+ win = XCreateWindow(dpy, parentwin, x, y, mw, mh, border_width,
|
||||||
|
CopyFromParent, CopyFromParent, CopyFromParent,
|
||||||
|
CWOverrideRedirect | CWBackPixel | CWEventMask, &swa);
|
||||||
|
+ XSetWindowBorder(dpy, win, scheme[SchemeSel][ColBg].pixel);
|
||||||
|
XSetClassHint(dpy, win, &ch);
|
||||||
|
|
||||||
|
/* open input methods */
|
||||||
Executable
+13
@@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
cachedir="${XDG_CACHE_HOME:-"$HOME/.cache"}"
|
||||||
|
cache="$cachedir/dmenu_run"
|
||||||
|
|
||||||
|
[ ! -e "$cachedir" ] && mkdir -p "$cachedir"
|
||||||
|
|
||||||
|
IFS=:
|
||||||
|
if stest -dqr -n "$cache" $PATH; then
|
||||||
|
stest -flx $PATH | sort -u | tee "$cache"
|
||||||
|
else
|
||||||
|
cat "$cache"
|
||||||
|
fi
|
||||||
Executable
+2
@@ -0,0 +1,2 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
dmenu_path | dmenu "$@" | ${SHELL:-"/bin/sh"} &
|
||||||
+425
@@ -0,0 +1,425 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include <X11/Xft/Xft.h>
|
||||||
|
|
||||||
|
#include "drw.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#define UTF_INVALID 0xFFFD
|
||||||
|
#define UTF_SIZ 4
|
||||||
|
|
||||||
|
static const unsigned char utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0};
|
||||||
|
static const unsigned char utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
|
||||||
|
static const long utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000};
|
||||||
|
static const long utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
|
||||||
|
|
||||||
|
static long
|
||||||
|
utf8decodebyte(const char c, size_t *i)
|
||||||
|
{
|
||||||
|
for (*i = 0; *i < (UTF_SIZ + 1); ++(*i))
|
||||||
|
if (((unsigned char)c & utfmask[*i]) == utfbyte[*i])
|
||||||
|
return (unsigned char)c & ~utfmask[*i];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
utf8validate(long *u, size_t i)
|
||||||
|
{
|
||||||
|
if (!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF))
|
||||||
|
*u = UTF_INVALID;
|
||||||
|
for (i = 1; *u > utfmax[i]; ++i)
|
||||||
|
;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
utf8decode(const char *c, long *u, size_t clen)
|
||||||
|
{
|
||||||
|
size_t i, j, len, type;
|
||||||
|
long udecoded;
|
||||||
|
|
||||||
|
*u = UTF_INVALID;
|
||||||
|
if (!clen)
|
||||||
|
return 0;
|
||||||
|
udecoded = utf8decodebyte(c[0], &len);
|
||||||
|
if (!BETWEEN(len, 1, UTF_SIZ))
|
||||||
|
return 1;
|
||||||
|
for (i = 1, j = 1; i < clen && j < len; ++i, ++j) {
|
||||||
|
udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type);
|
||||||
|
if (type)
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
if (j < len)
|
||||||
|
return 0;
|
||||||
|
*u = udecoded;
|
||||||
|
utf8validate(u, len);
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
Drw *
|
||||||
|
drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h, Visual *visual, unsigned int depth, Colormap cmap)
|
||||||
|
{
|
||||||
|
Drw *drw = ecalloc(1, sizeof(Drw));
|
||||||
|
|
||||||
|
drw->dpy = dpy;
|
||||||
|
drw->screen = screen;
|
||||||
|
drw->root = root;
|
||||||
|
drw->w = w;
|
||||||
|
drw->h = h;
|
||||||
|
drw->visual = visual;
|
||||||
|
drw->depth = depth;
|
||||||
|
drw->cmap = cmap;
|
||||||
|
drw->drawable = XCreatePixmap(dpy, root, w, h, depth);
|
||||||
|
drw->gc = XCreateGC(dpy, drw->drawable, 0, NULL);
|
||||||
|
XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter);
|
||||||
|
|
||||||
|
return drw;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
drw_resize(Drw *drw, unsigned int w, unsigned int h)
|
||||||
|
{
|
||||||
|
if (!drw)
|
||||||
|
return;
|
||||||
|
|
||||||
|
drw->w = w;
|
||||||
|
drw->h = h;
|
||||||
|
if (drw->drawable)
|
||||||
|
XFreePixmap(drw->dpy, drw->drawable);
|
||||||
|
drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, drw->depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
drw_free(Drw *drw)
|
||||||
|
{
|
||||||
|
XFreePixmap(drw->dpy, drw->drawable);
|
||||||
|
XFreeGC(drw->dpy, drw->gc);
|
||||||
|
drw_fontset_free(drw->fonts);
|
||||||
|
free(drw);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function is an implementation detail. Library users should use
|
||||||
|
* drw_fontset_create instead.
|
||||||
|
*/
|
||||||
|
static Fnt *
|
||||||
|
xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern)
|
||||||
|
{
|
||||||
|
Fnt *font;
|
||||||
|
XftFont *xfont = NULL;
|
||||||
|
FcPattern *pattern = NULL;
|
||||||
|
|
||||||
|
if (fontname) {
|
||||||
|
/* Using the pattern found at font->xfont->pattern does not yield the
|
||||||
|
* same substitution results as using the pattern returned by
|
||||||
|
* FcNameParse; using the latter results in the desired fallback
|
||||||
|
* behaviour whereas the former just results in missing-character
|
||||||
|
* rectangles being drawn, at least with some fonts. */
|
||||||
|
if (!(xfont = XftFontOpenName(drw->dpy, drw->screen, fontname))) {
|
||||||
|
fprintf(stderr, "error, cannot load font from name: '%s'\n", fontname);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (!(pattern = FcNameParse((FcChar8 *) fontname))) {
|
||||||
|
fprintf(stderr, "error, cannot parse font name to pattern: '%s'\n", fontname);
|
||||||
|
XftFontClose(drw->dpy, xfont);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
} else if (fontpattern) {
|
||||||
|
if (!(xfont = XftFontOpenPattern(drw->dpy, fontpattern))) {
|
||||||
|
fprintf(stderr, "error, cannot load font from pattern.\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
die("no font specified.");
|
||||||
|
}
|
||||||
|
|
||||||
|
font = ecalloc(1, sizeof(Fnt));
|
||||||
|
font->xfont = xfont;
|
||||||
|
font->pattern = pattern;
|
||||||
|
font->h = xfont->ascent + xfont->descent;
|
||||||
|
font->dpy = drw->dpy;
|
||||||
|
|
||||||
|
return font;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
xfont_free(Fnt *font)
|
||||||
|
{
|
||||||
|
if (!font)
|
||||||
|
return;
|
||||||
|
if (font->pattern)
|
||||||
|
FcPatternDestroy(font->pattern);
|
||||||
|
XftFontClose(font->dpy, font->xfont);
|
||||||
|
free(font);
|
||||||
|
}
|
||||||
|
|
||||||
|
Fnt*
|
||||||
|
drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount)
|
||||||
|
{
|
||||||
|
Fnt *cur, *ret = NULL;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if (!drw || !fonts)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for (i = 1; i <= fontcount; i++) {
|
||||||
|
if ((cur = xfont_create(drw, fonts[fontcount - i], NULL))) {
|
||||||
|
cur->next = ret;
|
||||||
|
ret = cur;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (drw->fonts = ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
drw_fontset_free(Fnt *font)
|
||||||
|
{
|
||||||
|
if (font) {
|
||||||
|
drw_fontset_free(font->next);
|
||||||
|
xfont_free(font);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
drw_clr_create(Drw *drw, Clr *dest, const char *clrname, unsigned int alpha)
|
||||||
|
{
|
||||||
|
if (!drw || !dest || !clrname)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!XftColorAllocName(drw->dpy, drw->visual, drw->cmap,
|
||||||
|
clrname, dest))
|
||||||
|
die("error, cannot allocate color '%s'", clrname);
|
||||||
|
|
||||||
|
dest->pixel = (dest->pixel & 0x00ffffffU) | (alpha << 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wrapper to create color schemes. The caller has to call free(3) on the
|
||||||
|
* returned color scheme when done using it. */
|
||||||
|
Clr *
|
||||||
|
drw_scm_create(Drw *drw, const char *clrnames[], const unsigned int alphas[], size_t clrcount)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
Clr *ret;
|
||||||
|
|
||||||
|
/* need at least two colors for a scheme */
|
||||||
|
if (!drw || !clrnames || clrcount < 2 || !(ret = ecalloc(clrcount, sizeof(XftColor))))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for (i = 0; i < clrcount; i++)
|
||||||
|
drw_clr_create(drw, &ret[i], clrnames[i], alphas[i]);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
drw_setfontset(Drw *drw, Fnt *set)
|
||||||
|
{
|
||||||
|
if (drw)
|
||||||
|
drw->fonts = set;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
drw_setscheme(Drw *drw, Clr *scm)
|
||||||
|
{
|
||||||
|
if (drw)
|
||||||
|
drw->scheme = scm;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert)
|
||||||
|
{
|
||||||
|
if (!drw || !drw->scheme)
|
||||||
|
return;
|
||||||
|
XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme[ColBg].pixel : drw->scheme[ColFg].pixel);
|
||||||
|
if (filled)
|
||||||
|
XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
|
||||||
|
else
|
||||||
|
XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w - 1, h - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert)
|
||||||
|
{
|
||||||
|
char buf[1024];
|
||||||
|
int ty;
|
||||||
|
unsigned int ew;
|
||||||
|
XftDraw *d = NULL;
|
||||||
|
Fnt *usedfont, *curfont, *nextfont;
|
||||||
|
size_t i, len;
|
||||||
|
int utf8strlen, utf8charlen, render = x || y || w || h;
|
||||||
|
long utf8codepoint = 0;
|
||||||
|
const char *utf8str;
|
||||||
|
FcCharSet *fccharset;
|
||||||
|
FcPattern *fcpattern;
|
||||||
|
FcPattern *match;
|
||||||
|
XftResult result;
|
||||||
|
int charexists = 0;
|
||||||
|
|
||||||
|
if (!drw || (render && !drw->scheme) || !text || !drw->fonts)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!render) {
|
||||||
|
w = ~w;
|
||||||
|
} else {
|
||||||
|
XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel);
|
||||||
|
XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
|
||||||
|
d = XftDrawCreate(drw->dpy, drw->drawable, drw->visual, drw->cmap);
|
||||||
|
x += lpad;
|
||||||
|
w -= lpad;
|
||||||
|
}
|
||||||
|
|
||||||
|
usedfont = drw->fonts;
|
||||||
|
while (1) {
|
||||||
|
utf8strlen = 0;
|
||||||
|
utf8str = text;
|
||||||
|
nextfont = NULL;
|
||||||
|
while (*text) {
|
||||||
|
utf8charlen = utf8decode(text, &utf8codepoint, UTF_SIZ);
|
||||||
|
for (curfont = drw->fonts; curfont; curfont = curfont->next) {
|
||||||
|
charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint);
|
||||||
|
if (charexists) {
|
||||||
|
if (curfont == usedfont) {
|
||||||
|
utf8strlen += utf8charlen;
|
||||||
|
text += utf8charlen;
|
||||||
|
} else {
|
||||||
|
nextfont = curfont;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!charexists || nextfont)
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
charexists = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (utf8strlen) {
|
||||||
|
drw_font_getexts(usedfont, utf8str, utf8strlen, &ew, NULL);
|
||||||
|
/* shorten text if necessary */
|
||||||
|
for (len = MIN(utf8strlen, sizeof(buf) - 1); len && ew > w; len--)
|
||||||
|
drw_font_getexts(usedfont, utf8str, len, &ew, NULL);
|
||||||
|
|
||||||
|
if (len) {
|
||||||
|
memcpy(buf, utf8str, len);
|
||||||
|
buf[len] = '\0';
|
||||||
|
if (len < utf8strlen)
|
||||||
|
for (i = len; i && i > len - 3; buf[--i] = '.')
|
||||||
|
; /* NOP */
|
||||||
|
|
||||||
|
if (render) {
|
||||||
|
ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent;
|
||||||
|
XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg],
|
||||||
|
usedfont->xfont, x, ty, (XftChar8 *)buf, len);
|
||||||
|
}
|
||||||
|
x += ew;
|
||||||
|
w -= ew;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!*text) {
|
||||||
|
break;
|
||||||
|
} else if (nextfont) {
|
||||||
|
charexists = 0;
|
||||||
|
usedfont = nextfont;
|
||||||
|
} else {
|
||||||
|
/* Regardless of whether or not a fallback font is found, the
|
||||||
|
* character must be drawn. */
|
||||||
|
charexists = 1;
|
||||||
|
|
||||||
|
fccharset = FcCharSetCreate();
|
||||||
|
FcCharSetAddChar(fccharset, utf8codepoint);
|
||||||
|
|
||||||
|
if (!drw->fonts->pattern) {
|
||||||
|
/* Refer to the comment in xfont_create for more information. */
|
||||||
|
die("the first font in the cache must be loaded from a font string.");
|
||||||
|
}
|
||||||
|
|
||||||
|
fcpattern = FcPatternDuplicate(drw->fonts->pattern);
|
||||||
|
FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset);
|
||||||
|
FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue);
|
||||||
|
FcPatternAddBool(fcpattern, FC_COLOR, FcFalse);
|
||||||
|
|
||||||
|
FcConfigSubstitute(NULL, fcpattern, FcMatchPattern);
|
||||||
|
FcDefaultSubstitute(fcpattern);
|
||||||
|
match = XftFontMatch(drw->dpy, drw->screen, fcpattern, &result);
|
||||||
|
|
||||||
|
FcCharSetDestroy(fccharset);
|
||||||
|
FcPatternDestroy(fcpattern);
|
||||||
|
|
||||||
|
if (match) {
|
||||||
|
usedfont = xfont_create(drw, NULL, match);
|
||||||
|
if (usedfont && XftCharExists(drw->dpy, usedfont->xfont, utf8codepoint)) {
|
||||||
|
for (curfont = drw->fonts; curfont->next; curfont = curfont->next)
|
||||||
|
; /* NOP */
|
||||||
|
curfont->next = usedfont;
|
||||||
|
} else {
|
||||||
|
xfont_free(usedfont);
|
||||||
|
usedfont = drw->fonts;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (d)
|
||||||
|
XftDrawDestroy(d);
|
||||||
|
|
||||||
|
return x + (render ? w : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h)
|
||||||
|
{
|
||||||
|
if (!drw)
|
||||||
|
return;
|
||||||
|
|
||||||
|
XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, y);
|
||||||
|
XSync(drw->dpy, False);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
drw_fontset_getwidth(Drw *drw, const char *text)
|
||||||
|
{
|
||||||
|
if (!drw || !drw->fonts || !text)
|
||||||
|
return 0;
|
||||||
|
return drw_text(drw, 0, 0, 0, 0, 0, text, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h)
|
||||||
|
{
|
||||||
|
XGlyphInfo ext;
|
||||||
|
|
||||||
|
if (!font || !text)
|
||||||
|
return;
|
||||||
|
|
||||||
|
XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *)text, len, &ext);
|
||||||
|
if (w)
|
||||||
|
*w = ext.xOff;
|
||||||
|
if (h)
|
||||||
|
*h = font->h;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cur *
|
||||||
|
drw_cur_create(Drw *drw, int shape)
|
||||||
|
{
|
||||||
|
Cur *cur;
|
||||||
|
|
||||||
|
if (!drw || !(cur = ecalloc(1, sizeof(Cur))))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
cur->cursor = XCreateFontCursor(drw->dpy, shape);
|
||||||
|
|
||||||
|
return cur;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
drw_cur_free(Drw *drw, Cur *cursor)
|
||||||
|
{
|
||||||
|
if (!cursor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
XFreeCursor(drw->dpy, cursor->cursor);
|
||||||
|
free(cursor);
|
||||||
|
}
|
||||||
@@ -0,0 +1,423 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include <X11/Xft/Xft.h>
|
||||||
|
|
||||||
|
#include "drw.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#define UTF_INVALID 0xFFFD
|
||||||
|
#define UTF_SIZ 4
|
||||||
|
|
||||||
|
static const unsigned char utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0};
|
||||||
|
static const unsigned char utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
|
||||||
|
static const long utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000};
|
||||||
|
static const long utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
|
||||||
|
|
||||||
|
static long
|
||||||
|
utf8decodebyte(const char c, size_t *i)
|
||||||
|
{
|
||||||
|
for (*i = 0; *i < (UTF_SIZ + 1); ++(*i))
|
||||||
|
if (((unsigned char)c & utfmask[*i]) == utfbyte[*i])
|
||||||
|
return (unsigned char)c & ~utfmask[*i];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
utf8validate(long *u, size_t i)
|
||||||
|
{
|
||||||
|
if (!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF))
|
||||||
|
*u = UTF_INVALID;
|
||||||
|
for (i = 1; *u > utfmax[i]; ++i)
|
||||||
|
;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
utf8decode(const char *c, long *u, size_t clen)
|
||||||
|
{
|
||||||
|
size_t i, j, len, type;
|
||||||
|
long udecoded;
|
||||||
|
|
||||||
|
*u = UTF_INVALID;
|
||||||
|
if (!clen)
|
||||||
|
return 0;
|
||||||
|
udecoded = utf8decodebyte(c[0], &len);
|
||||||
|
if (!BETWEEN(len, 1, UTF_SIZ))
|
||||||
|
return 1;
|
||||||
|
for (i = 1, j = 1; i < clen && j < len; ++i, ++j) {
|
||||||
|
udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type);
|
||||||
|
if (type)
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
if (j < len)
|
||||||
|
return 0;
|
||||||
|
*u = udecoded;
|
||||||
|
utf8validate(u, len);
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
Drw *
|
||||||
|
drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h)
|
||||||
|
{
|
||||||
|
Drw *drw = ecalloc(1, sizeof(Drw));
|
||||||
|
|
||||||
|
drw->dpy = dpy;
|
||||||
|
drw->screen = screen;
|
||||||
|
drw->root = root;
|
||||||
|
drw->w = w;
|
||||||
|
drw->h = h;
|
||||||
|
drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen));
|
||||||
|
drw->gc = XCreateGC(dpy, root, 0, NULL);
|
||||||
|
XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter);
|
||||||
|
|
||||||
|
return drw;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
drw_resize(Drw *drw, unsigned int w, unsigned int h)
|
||||||
|
{
|
||||||
|
if (!drw)
|
||||||
|
return;
|
||||||
|
|
||||||
|
drw->w = w;
|
||||||
|
drw->h = h;
|
||||||
|
if (drw->drawable)
|
||||||
|
XFreePixmap(drw->dpy, drw->drawable);
|
||||||
|
drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, DefaultDepth(drw->dpy, drw->screen));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
drw_free(Drw *drw)
|
||||||
|
{
|
||||||
|
XFreePixmap(drw->dpy, drw->drawable);
|
||||||
|
XFreeGC(drw->dpy, drw->gc);
|
||||||
|
drw_fontset_free(drw->fonts);
|
||||||
|
free(drw);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function is an implementation detail. Library users should use
|
||||||
|
* drw_fontset_create instead.
|
||||||
|
*/
|
||||||
|
static Fnt *
|
||||||
|
xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern)
|
||||||
|
{
|
||||||
|
Fnt *font;
|
||||||
|
XftFont *xfont = NULL;
|
||||||
|
FcPattern *pattern = NULL;
|
||||||
|
|
||||||
|
if (fontname) {
|
||||||
|
/* Using the pattern found at font->xfont->pattern does not yield the
|
||||||
|
* same substitution results as using the pattern returned by
|
||||||
|
* FcNameParse; using the latter results in the desired fallback
|
||||||
|
* behaviour whereas the former just results in missing-character
|
||||||
|
* rectangles being drawn, at least with some fonts. */
|
||||||
|
if (!(xfont = XftFontOpenName(drw->dpy, drw->screen, fontname))) {
|
||||||
|
fprintf(stderr, "error, cannot load font from name: '%s'\n", fontname);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (!(pattern = FcNameParse((FcChar8 *) fontname))) {
|
||||||
|
fprintf(stderr, "error, cannot parse font name to pattern: '%s'\n", fontname);
|
||||||
|
XftFontClose(drw->dpy, xfont);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
} else if (fontpattern) {
|
||||||
|
if (!(xfont = XftFontOpenPattern(drw->dpy, fontpattern))) {
|
||||||
|
fprintf(stderr, "error, cannot load font from pattern.\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
die("no font specified.");
|
||||||
|
}
|
||||||
|
|
||||||
|
font = ecalloc(1, sizeof(Fnt));
|
||||||
|
font->xfont = xfont;
|
||||||
|
font->pattern = pattern;
|
||||||
|
font->h = xfont->ascent + xfont->descent;
|
||||||
|
font->dpy = drw->dpy;
|
||||||
|
|
||||||
|
return font;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
xfont_free(Fnt *font)
|
||||||
|
{
|
||||||
|
if (!font)
|
||||||
|
return;
|
||||||
|
if (font->pattern)
|
||||||
|
FcPatternDestroy(font->pattern);
|
||||||
|
XftFontClose(font->dpy, font->xfont);
|
||||||
|
free(font);
|
||||||
|
}
|
||||||
|
|
||||||
|
Fnt*
|
||||||
|
drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount)
|
||||||
|
{
|
||||||
|
Fnt *cur, *ret = NULL;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if (!drw || !fonts)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for (i = 1; i <= fontcount; i++) {
|
||||||
|
if ((cur = xfont_create(drw, fonts[fontcount - i], NULL))) {
|
||||||
|
cur->next = ret;
|
||||||
|
ret = cur;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (drw->fonts = ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
drw_fontset_free(Fnt *font)
|
||||||
|
{
|
||||||
|
if (font) {
|
||||||
|
drw_fontset_free(font->next);
|
||||||
|
xfont_free(font);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
drw_clr_create(Drw *drw, Clr *dest, const char *clrname)
|
||||||
|
{
|
||||||
|
if (!drw || !dest || !clrname)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen),
|
||||||
|
DefaultColormap(drw->dpy, drw->screen),
|
||||||
|
clrname, dest))
|
||||||
|
die("error, cannot allocate color '%s'", clrname);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wrapper to create color schemes. The caller has to call free(3) on the
|
||||||
|
* returned color scheme when done using it. */
|
||||||
|
Clr *
|
||||||
|
drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
Clr *ret;
|
||||||
|
|
||||||
|
/* need at least two colors for a scheme */
|
||||||
|
if (!drw || !clrnames || clrcount < 2 || !(ret = ecalloc(clrcount, sizeof(XftColor))))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for (i = 0; i < clrcount; i++)
|
||||||
|
drw_clr_create(drw, &ret[i], clrnames[i]);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
drw_setfontset(Drw *drw, Fnt *set)
|
||||||
|
{
|
||||||
|
if (drw)
|
||||||
|
drw->fonts = set;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
drw_setscheme(Drw *drw, Clr *scm)
|
||||||
|
{
|
||||||
|
if (drw)
|
||||||
|
drw->scheme = scm;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert)
|
||||||
|
{
|
||||||
|
if (!drw || !drw->scheme)
|
||||||
|
return;
|
||||||
|
XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme[ColBg].pixel : drw->scheme[ColFg].pixel);
|
||||||
|
if (filled)
|
||||||
|
XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
|
||||||
|
else
|
||||||
|
XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w - 1, h - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert)
|
||||||
|
{
|
||||||
|
char buf[1024];
|
||||||
|
int ty;
|
||||||
|
unsigned int ew;
|
||||||
|
XftDraw *d = NULL;
|
||||||
|
Fnt *usedfont, *curfont, *nextfont;
|
||||||
|
size_t i, len;
|
||||||
|
int utf8strlen, utf8charlen, render = x || y || w || h;
|
||||||
|
long utf8codepoint = 0;
|
||||||
|
const char *utf8str;
|
||||||
|
FcCharSet *fccharset;
|
||||||
|
FcPattern *fcpattern;
|
||||||
|
FcPattern *match;
|
||||||
|
XftResult result;
|
||||||
|
int charexists = 0;
|
||||||
|
|
||||||
|
if (!drw || (render && !drw->scheme) || !text || !drw->fonts)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!render) {
|
||||||
|
w = ~w;
|
||||||
|
} else {
|
||||||
|
XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel);
|
||||||
|
XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
|
||||||
|
d = XftDrawCreate(drw->dpy, drw->drawable,
|
||||||
|
DefaultVisual(drw->dpy, drw->screen),
|
||||||
|
DefaultColormap(drw->dpy, drw->screen));
|
||||||
|
x += lpad;
|
||||||
|
w -= lpad;
|
||||||
|
}
|
||||||
|
|
||||||
|
usedfont = drw->fonts;
|
||||||
|
while (1) {
|
||||||
|
utf8strlen = 0;
|
||||||
|
utf8str = text;
|
||||||
|
nextfont = NULL;
|
||||||
|
while (*text) {
|
||||||
|
utf8charlen = utf8decode(text, &utf8codepoint, UTF_SIZ);
|
||||||
|
for (curfont = drw->fonts; curfont; curfont = curfont->next) {
|
||||||
|
charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint);
|
||||||
|
if (charexists) {
|
||||||
|
if (curfont == usedfont) {
|
||||||
|
utf8strlen += utf8charlen;
|
||||||
|
text += utf8charlen;
|
||||||
|
} else {
|
||||||
|
nextfont = curfont;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!charexists || nextfont)
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
charexists = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (utf8strlen) {
|
||||||
|
drw_font_getexts(usedfont, utf8str, utf8strlen, &ew, NULL);
|
||||||
|
/* shorten text if necessary */
|
||||||
|
for (len = MIN(utf8strlen, sizeof(buf) - 1); len && ew > w; len--)
|
||||||
|
drw_font_getexts(usedfont, utf8str, len, &ew, NULL);
|
||||||
|
|
||||||
|
if (len) {
|
||||||
|
memcpy(buf, utf8str, len);
|
||||||
|
buf[len] = '\0';
|
||||||
|
if (len < utf8strlen)
|
||||||
|
for (i = len; i && i > len - 3; buf[--i] = '.')
|
||||||
|
; /* NOP */
|
||||||
|
|
||||||
|
if (render) {
|
||||||
|
ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent;
|
||||||
|
XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg],
|
||||||
|
usedfont->xfont, x, ty, (XftChar8 *)buf, len);
|
||||||
|
}
|
||||||
|
x += ew;
|
||||||
|
w -= ew;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!*text) {
|
||||||
|
break;
|
||||||
|
} else if (nextfont) {
|
||||||
|
charexists = 0;
|
||||||
|
usedfont = nextfont;
|
||||||
|
} else {
|
||||||
|
/* Regardless of whether or not a fallback font is found, the
|
||||||
|
* character must be drawn. */
|
||||||
|
charexists = 1;
|
||||||
|
|
||||||
|
fccharset = FcCharSetCreate();
|
||||||
|
FcCharSetAddChar(fccharset, utf8codepoint);
|
||||||
|
|
||||||
|
if (!drw->fonts->pattern) {
|
||||||
|
/* Refer to the comment in xfont_create for more information. */
|
||||||
|
die("the first font in the cache must be loaded from a font string.");
|
||||||
|
}
|
||||||
|
|
||||||
|
fcpattern = FcPatternDuplicate(drw->fonts->pattern);
|
||||||
|
FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset);
|
||||||
|
FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue);
|
||||||
|
FcPatternAddBool(fcpattern, FC_COLOR, FcFalse);
|
||||||
|
|
||||||
|
FcConfigSubstitute(NULL, fcpattern, FcMatchPattern);
|
||||||
|
FcDefaultSubstitute(fcpattern);
|
||||||
|
match = XftFontMatch(drw->dpy, drw->screen, fcpattern, &result);
|
||||||
|
|
||||||
|
FcCharSetDestroy(fccharset);
|
||||||
|
FcPatternDestroy(fcpattern);
|
||||||
|
|
||||||
|
if (match) {
|
||||||
|
usedfont = xfont_create(drw, NULL, match);
|
||||||
|
if (usedfont && XftCharExists(drw->dpy, usedfont->xfont, utf8codepoint)) {
|
||||||
|
for (curfont = drw->fonts; curfont->next; curfont = curfont->next)
|
||||||
|
; /* NOP */
|
||||||
|
curfont->next = usedfont;
|
||||||
|
} else {
|
||||||
|
xfont_free(usedfont);
|
||||||
|
usedfont = drw->fonts;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (d)
|
||||||
|
XftDrawDestroy(d);
|
||||||
|
|
||||||
|
return x + (render ? w : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h)
|
||||||
|
{
|
||||||
|
if (!drw)
|
||||||
|
return;
|
||||||
|
|
||||||
|
XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, y);
|
||||||
|
XSync(drw->dpy, False);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
drw_fontset_getwidth(Drw *drw, const char *text)
|
||||||
|
{
|
||||||
|
if (!drw || !drw->fonts || !text)
|
||||||
|
return 0;
|
||||||
|
return drw_text(drw, 0, 0, 0, 0, 0, text, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h)
|
||||||
|
{
|
||||||
|
XGlyphInfo ext;
|
||||||
|
|
||||||
|
if (!font || !text)
|
||||||
|
return;
|
||||||
|
|
||||||
|
XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *)text, len, &ext);
|
||||||
|
if (w)
|
||||||
|
*w = ext.xOff;
|
||||||
|
if (h)
|
||||||
|
*h = font->h;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cur *
|
||||||
|
drw_cur_create(Drw *drw, int shape)
|
||||||
|
{
|
||||||
|
Cur *cur;
|
||||||
|
|
||||||
|
if (!drw || !(cur = ecalloc(1, sizeof(Cur))))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
cur->cursor = XCreateFontCursor(drw->dpy, shape);
|
||||||
|
|
||||||
|
return cur;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
drw_cur_free(Drw *drw, Cur *cursor)
|
||||||
|
{
|
||||||
|
if (!cursor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
XFreeCursor(drw->dpy, cursor->cursor);
|
||||||
|
free(cursor);
|
||||||
|
}
|
||||||
+60
@@ -0,0 +1,60 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Cursor cursor;
|
||||||
|
} Cur;
|
||||||
|
|
||||||
|
typedef struct Fnt {
|
||||||
|
Display *dpy;
|
||||||
|
unsigned int h;
|
||||||
|
XftFont *xfont;
|
||||||
|
FcPattern *pattern;
|
||||||
|
struct Fnt *next;
|
||||||
|
} Fnt;
|
||||||
|
|
||||||
|
enum { ColFg, ColBg }; /* Clr scheme index */
|
||||||
|
typedef XftColor Clr;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned int w, h;
|
||||||
|
Display *dpy;
|
||||||
|
int screen;
|
||||||
|
Window root;
|
||||||
|
Visual *visual;
|
||||||
|
unsigned int depth;
|
||||||
|
Colormap cmap;
|
||||||
|
Drawable drawable;
|
||||||
|
GC gc;
|
||||||
|
Clr *scheme;
|
||||||
|
Fnt *fonts;
|
||||||
|
} Drw;
|
||||||
|
|
||||||
|
/* Drawable abstraction */
|
||||||
|
Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h, Visual*, unsigned int, Colormap);
|
||||||
|
void drw_resize(Drw *drw, unsigned int w, unsigned int h);
|
||||||
|
void drw_free(Drw *drw);
|
||||||
|
|
||||||
|
/* Fnt abstraction */
|
||||||
|
Fnt *drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount);
|
||||||
|
void drw_fontset_free(Fnt* set);
|
||||||
|
unsigned int drw_fontset_getwidth(Drw *drw, const char *text);
|
||||||
|
void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h);
|
||||||
|
|
||||||
|
/* Colorscheme abstraction */
|
||||||
|
void drw_clr_create(Drw *drw, Clr *dest, const char *clrname, unsigned int alpha);
|
||||||
|
Clr *drw_scm_create(Drw *drw, const char *clrnames[], const unsigned int alphas[], size_t clrcount);
|
||||||
|
|
||||||
|
/* Cursor abstraction */
|
||||||
|
Cur *drw_cur_create(Drw *drw, int shape);
|
||||||
|
void drw_cur_free(Drw *drw, Cur *cursor);
|
||||||
|
|
||||||
|
/* Drawing context manipulation */
|
||||||
|
void drw_setfontset(Drw *drw, Fnt *set);
|
||||||
|
void drw_setscheme(Drw *drw, Clr *scm);
|
||||||
|
|
||||||
|
/* Drawing functions */
|
||||||
|
void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert);
|
||||||
|
int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert);
|
||||||
|
|
||||||
|
/* Map functions */
|
||||||
|
void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h);
|
||||||
@@ -0,0 +1,267 @@
|
|||||||
|
diff --git a/config.def.h b/config.def.h
|
||||||
|
index 1edb647..697d511 100644
|
||||||
|
--- a/config.def.h
|
||||||
|
+++ b/config.def.h
|
||||||
|
@@ -2,6 +2,7 @@
|
||||||
|
/* Default settings; can be overriden by command line. */
|
||||||
|
|
||||||
|
static int topbar = 1; /* -b option; if 0, dmenu appears at bottom */
|
||||||
|
+static const unsigned int alpha = 0xf0;
|
||||||
|
/* -fn option overrides fonts[0]; default X11 font or font set */
|
||||||
|
static const char *fonts[] = {
|
||||||
|
"monospace:size=10"
|
||||||
|
@@ -13,6 +14,13 @@ static const char *colors[SchemeLast][2] = {
|
||||||
|
[SchemeSel] = { "#eeeeee", "#005577" },
|
||||||
|
[SchemeOut] = { "#000000", "#00ffff" },
|
||||||
|
};
|
||||||
|
+
|
||||||
|
+static const unsigned int alphas[SchemeLast][2] = {
|
||||||
|
+ [SchemeNorm] = { OPAQUE, alpha },
|
||||||
|
+ [SchemeSel] = { OPAQUE, alpha },
|
||||||
|
+ [SchemeOut] = { OPAQUE, alpha },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
/* -l option; if nonzero, dmenu uses vertical list with given number of lines */
|
||||||
|
static unsigned int lines = 0;
|
||||||
|
|
||||||
|
diff --git a/dmenu.c b/dmenu.c
|
||||||
|
index 65f25ce..3e56e1a 100644
|
||||||
|
--- a/dmenu.c
|
||||||
|
+++ b/dmenu.c
|
||||||
|
@@ -10,6 +10,7 @@
|
||||||
|
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include <X11/Xatom.h>
|
||||||
|
+#include <X11/Xproto.h>
|
||||||
|
#include <X11/Xutil.h>
|
||||||
|
#ifdef XINERAMA
|
||||||
|
#include <X11/extensions/Xinerama.h>
|
||||||
|
@@ -25,6 +26,8 @@
|
||||||
|
#define LENGTH(X) (sizeof X / sizeof X[0])
|
||||||
|
#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
|
||||||
|
|
||||||
|
+#define OPAQUE 0xffU
|
||||||
|
+
|
||||||
|
/* enums */
|
||||||
|
enum { SchemeNorm, SchemeSel, SchemeOut, SchemeLast }; /* color schemes */
|
||||||
|
|
||||||
|
@@ -53,10 +56,16 @@ static XIC xic;
|
||||||
|
static Drw *drw;
|
||||||
|
static Clr *scheme[SchemeLast];
|
||||||
|
|
||||||
|
+static int useargb = 0;
|
||||||
|
+static Visual *visual;
|
||||||
|
+static int depth;
|
||||||
|
+static Colormap cmap;
|
||||||
|
+
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
static int (*fstrncmp)(const char *, const char *, size_t) = strncmp;
|
||||||
|
static char *(*fstrstr)(const char *, const char *) = strstr;
|
||||||
|
+static void xinitvisual();
|
||||||
|
|
||||||
|
static void
|
||||||
|
appenditem(struct item *item, struct item **list, struct item **last)
|
||||||
|
@@ -602,7 +611,7 @@ setup(void)
|
||||||
|
#endif
|
||||||
|
/* init appearance */
|
||||||
|
for (j = 0; j < SchemeLast; j++)
|
||||||
|
- scheme[j] = drw_scm_create(drw, colors[j], 2);
|
||||||
|
+ scheme[j] = drw_scm_create(drw, colors[j], alphas[i], 2);
|
||||||
|
|
||||||
|
clip = XInternAtom(dpy, "CLIPBOARD", False);
|
||||||
|
utf8 = XInternAtom(dpy, "UTF8_STRING", False);
|
||||||
|
@@ -640,6 +649,7 @@ setup(void)
|
||||||
|
x = info[i].x_org;
|
||||||
|
y = info[i].y_org + (topbar ? 0 : info[i].height - mh);
|
||||||
|
mw = info[i].width;
|
||||||
|
+
|
||||||
|
XFree(info);
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
@@ -657,11 +667,13 @@ setup(void)
|
||||||
|
|
||||||
|
/* create menu window */
|
||||||
|
swa.override_redirect = True;
|
||||||
|
- swa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
|
||||||
|
+ swa.background_pixel = 0;
|
||||||
|
+ swa.border_pixel = 0;
|
||||||
|
+ swa.colormap = cmap;
|
||||||
|
swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask;
|
||||||
|
- win = XCreateWindow(dpy, parentwin, x, y, mw, mh, 0,
|
||||||
|
- CopyFromParent, CopyFromParent, CopyFromParent,
|
||||||
|
- CWOverrideRedirect | CWBackPixel | CWEventMask, &swa);
|
||||||
|
+ win = XCreateWindow(dpy, parentwin, x, y, mw, mh, border_width,
|
||||||
|
+ depth, CopyFromParent, visual,
|
||||||
|
+ CWOverrideRedirect | CWBackPixel | CWBorderPixel | CWColormap | CWEventMask, &swa);
|
||||||
|
XSetClassHint(dpy, win, &ch);
|
||||||
|
|
||||||
|
|
||||||
|
@@ -747,7 +759,8 @@ main(int argc, char *argv[])
|
||||||
|
if (!XGetWindowAttributes(dpy, parentwin, &wa))
|
||||||
|
die("could not get embedding window attributes: 0x%lx",
|
||||||
|
parentwin);
|
||||||
|
- drw = drw_create(dpy, screen, root, wa.width, wa.height);
|
||||||
|
+ xinitvisual();
|
||||||
|
+ drw = drw_create(dpy, screen, root, wa.width, wa.height, visual, depth, cmap);
|
||||||
|
if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
|
||||||
|
die("no fonts could be loaded.");
|
||||||
|
lrpad = drw->fonts->h;
|
||||||
|
@@ -769,3 +782,40 @@ main(int argc, char *argv[])
|
||||||
|
|
||||||
|
return 1; /* unreachable */
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ void
|
||||||
|
+xinitvisual()
|
||||||
|
+{
|
||||||
|
+ XVisualInfo *infos;
|
||||||
|
+ XRenderPictFormat *fmt;
|
||||||
|
+ int nitems;
|
||||||
|
+ int i;
|
||||||
|
+
|
||||||
|
+ XVisualInfo tpl = {
|
||||||
|
+ .screen = screen,
|
||||||
|
+ .depth = 32,
|
||||||
|
+ .class = TrueColor
|
||||||
|
+ };
|
||||||
|
+ long masks = VisualScreenMask | VisualDepthMask | VisualClassMask;
|
||||||
|
+
|
||||||
|
+ infos = XGetVisualInfo(dpy, masks, &tpl, &nitems);
|
||||||
|
+ visual = NULL;
|
||||||
|
+ for(i = 0; i < nitems; i ++) {
|
||||||
|
+ fmt = XRenderFindVisualFormat(dpy, infos[i].visual);
|
||||||
|
+ if (fmt->type == PictTypeDirect && fmt->direct.alphaMask) {
|
||||||
|
+ visual = infos[i].visual;
|
||||||
|
+ depth = infos[i].depth;
|
||||||
|
+ cmap = XCreateColormap(dpy, root, visual, AllocNone);
|
||||||
|
+ useargb = 1;
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ XFree(infos);
|
||||||
|
+
|
||||||
|
+ if (! visual) {
|
||||||
|
+ visual = DefaultVisual(dpy, screen);
|
||||||
|
+ depth = DefaultDepth(dpy, screen);
|
||||||
|
+ cmap = DefaultColormap(dpy, screen);
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
diff --git a/drw.c b/drw.c
|
||||||
|
index 4cdbcbe..fe3aadd 100644
|
||||||
|
--- a/drw.c
|
||||||
|
+++ b/drw.c
|
||||||
|
@@ -61,7 +61,7 @@ utf8decode(const char *c, long *u, size_t clen)
|
||||||
|
}
|
||||||
|
|
||||||
|
Drw *
|
||||||
|
-drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h)
|
||||||
|
+drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h, Visual *visual, unsigned int depth, Colormap cmap)
|
||||||
|
{
|
||||||
|
Drw *drw = ecalloc(1, sizeof(Drw));
|
||||||
|
|
||||||
|
@@ -70,8 +70,11 @@ drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h
|
||||||
|
drw->root = root;
|
||||||
|
drw->w = w;
|
||||||
|
drw->h = h;
|
||||||
|
- drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen));
|
||||||
|
- drw->gc = XCreateGC(dpy, root, 0, NULL);
|
||||||
|
+ drw->visual = visual;
|
||||||
|
+ drw->depth = depth;
|
||||||
|
+ drw->cmap = cmap;
|
||||||
|
+ drw->drawable = XCreatePixmap(dpy, root, w, h, depth);
|
||||||
|
+ drw->gc = XCreateGC(dpy, drw->drawable, 0, NULL);
|
||||||
|
XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter);
|
||||||
|
|
||||||
|
return drw;
|
||||||
|
@@ -87,7 +90,7 @@ drw_resize(Drw *drw, unsigned int w, unsigned int h)
|
||||||
|
drw->h = h;
|
||||||
|
if (drw->drawable)
|
||||||
|
XFreePixmap(drw->dpy, drw->drawable);
|
||||||
|
- drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, DefaultDepth(drw->dpy, drw->screen));
|
||||||
|
+ drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, drw->depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
@@ -194,21 +197,22 @@ drw_fontset_free(Fnt *font)
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
-drw_clr_create(Drw *drw, Clr *dest, const char *clrname)
|
||||||
|
+drw_clr_create(Drw *drw, Clr *dest, const char *clrname, unsigned int alpha)
|
||||||
|
{
|
||||||
|
if (!drw || !dest || !clrname)
|
||||||
|
return;
|
||||||
|
|
||||||
|
- if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen),
|
||||||
|
- DefaultColormap(drw->dpy, drw->screen),
|
||||||
|
+ if (!XftColorAllocName(drw->dpy, drw->visual, drw->cmap,
|
||||||
|
clrname, dest))
|
||||||
|
die("error, cannot allocate color '%s'", clrname);
|
||||||
|
+
|
||||||
|
+ dest->pixel = (dest->pixel & 0x00ffffffU) | (alpha << 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wrapper to create color schemes. The caller has to call free(3) on the
|
||||||
|
* returned color scheme when done using it. */
|
||||||
|
Clr *
|
||||||
|
-drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount)
|
||||||
|
+drw_scm_create(Drw *drw, const char *clrnames[], const unsigned int alphas[], size_t clrcount)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
Clr *ret;
|
||||||
|
@@ -218,7 +222,7 @@ drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for (i = 0; i < clrcount; i++)
|
||||||
|
- drw_clr_create(drw, &ret[i], clrnames[i]);
|
||||||
|
+ drw_clr_create(drw, &ret[i], clrnames[i], alphas[i]);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -274,9 +278,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
|
||||||
|
} else {
|
||||||
|
XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel);
|
||||||
|
XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
|
||||||
|
- d = XftDrawCreate(drw->dpy, drw->drawable,
|
||||||
|
- DefaultVisual(drw->dpy, drw->screen),
|
||||||
|
- DefaultColormap(drw->dpy, drw->screen));
|
||||||
|
+ d = XftDrawCreate(drw->dpy, drw->drawable, drw->visual, drw->cmap);
|
||||||
|
x += lpad;
|
||||||
|
w -= lpad;
|
||||||
|
}
|
||||||
|
diff --git a/drw.h b/drw.h
|
||||||
|
index 4c67419..f6fa5cd 100644
|
||||||
|
--- a/drw.h
|
||||||
|
+++ b/drw.h
|
||||||
|
@@ -20,6 +20,9 @@ typedef struct {
|
||||||
|
Display *dpy;
|
||||||
|
int screen;
|
||||||
|
Window root;
|
||||||
|
+ Visual *visual;
|
||||||
|
+ unsigned int depth;
|
||||||
|
+ Colormap cmap;
|
||||||
|
Drawable drawable;
|
||||||
|
GC gc;
|
||||||
|
Clr *scheme;
|
||||||
|
@@ -27,7 +30,7 @@ typedef struct {
|
||||||
|
} Drw;
|
||||||
|
|
||||||
|
/* Drawable abstraction */
|
||||||
|
-Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h);
|
||||||
|
+Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h, Visual*, unsigned int, Colormap);
|
||||||
|
void drw_resize(Drw *drw, unsigned int w, unsigned int h);
|
||||||
|
void drw_free(Drw *drw);
|
||||||
|
|
||||||
|
@@ -38,8 +41,8 @@ unsigned int drw_fontset_getwidth(Drw *drw, const char *text);
|
||||||
|
void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h);
|
||||||
|
|
||||||
|
/* Colorscheme abstraction */
|
||||||
|
-void drw_clr_create(Drw *drw, Clr *dest, const char *clrname);
|
||||||
|
-Clr *drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount);
|
||||||
|
+void drw_clr_create(Drw *drw, Clr *dest, const char *clrname, unsigned int alpha);
|
||||||
|
+Clr *drw_scm_create(Drw *drw, const char *clrnames[], const unsigned int alphas[], size_t clrcount);
|
||||||
|
|
||||||
|
/* Cursor abstraction */
|
||||||
|
Cur *drw_cur_create(Drw *drw, int shape);
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
diff -up dmenu-4.9-b/config.def.h dmenu-4.9-a/config.def.h
|
||||||
|
--- dmenu-4.9-b/config.def.h 2019-02-02 13:55:02.000000000 +0100
|
||||||
|
+++ dmenu-4.9-a/config.def.h 2019-05-19 02:10:12.740040403 +0200
|
||||||
|
@@ -21,3 +21,6 @@ static unsigned int lines = 0;
|
||||||
|
* for example: " /?\"&[]"
|
||||||
|
*/
|
||||||
|
static const char worddelimiters[] = " ";
|
||||||
|
+
|
||||||
|
+/* Size of the window border */
|
||||||
|
+static const unsigned int border_width = 5;
|
||||||
|
diff -up dmenu-4.9-b/dmenu.c dmenu-4.9-a/dmenu.c
|
||||||
|
--- dmenu-4.9-b/dmenu.c 2019-02-02 13:55:02.000000000 +0100
|
||||||
|
+++ dmenu-4.9-a/dmenu.c 2019-05-19 02:11:20.966710117 +0200
|
||||||
|
@@ -654,9 +654,10 @@ setup(void)
|
||||||
|
swa.override_redirect = True;
|
||||||
|
swa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
|
||||||
|
swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask;
|
||||||
|
- win = XCreateWindow(dpy, parentwin, x, y, mw, mh, 0,
|
||||||
|
+ win = XCreateWindow(dpy, parentwin, x, y, mw, mh, border_width,
|
||||||
|
CopyFromParent, CopyFromParent, CopyFromParent,
|
||||||
|
CWOverrideRedirect | CWBackPixel | CWEventMask, &swa);
|
||||||
|
+ XSetWindowBorder(dpy, win, scheme[SchemeSel][ColBg].pixel);
|
||||||
|
XSetClassHint(dpy, win, &ch);
|
||||||
|
|
||||||
|
/* open input methods */
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
diff --git a/dmenu.c b/dmenu.c
|
||||||
|
index 5e9c367..2268ea9 100644
|
||||||
|
--- a/dmenu.c
|
||||||
|
+++ b/dmenu.c
|
||||||
|
@@ -88,6 +88,15 @@ calcoffsets(void)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int
|
||||||
|
+max_textw(void)
|
||||||
|
+{
|
||||||
|
+ int len = 0;
|
||||||
|
+ for (struct item *item = items; item && item->text; item++)
|
||||||
|
+ len = MAX(TEXTW(item->text), len);
|
||||||
|
+ return len;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static void
|
||||||
|
cleanup(void)
|
||||||
|
{
|
||||||
|
@@ -598,6 +607,7 @@ setup(void)
|
||||||
|
bh = drw->fonts->h + 2;
|
||||||
|
lines = MAX(lines, 0);
|
||||||
|
mh = (lines + 1) * bh;
|
||||||
|
+ promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0;
|
||||||
|
#ifdef XINERAMA
|
||||||
|
i = 0;
|
||||||
|
if (parentwin == root && (info = XineramaQueryScreens(dpy, &n))) {
|
||||||
|
@@ -624,9 +634,9 @@ setup(void)
|
||||||
|
if (INTERSECT(x, y, 1, 1, info[i]))
|
||||||
|
break;
|
||||||
|
|
||||||
|
- x = info[i].x_org;
|
||||||
|
- y = info[i].y_org + (topbar ? 0 : info[i].height - mh);
|
||||||
|
- mw = info[i].width;
|
||||||
|
+ mw = MIN(MAX(max_textw() + promptw, 100), info[i].width);
|
||||||
|
+ x = info[i].x_org + ((info[i].width - mw) / 2);
|
||||||
|
+ y = info[i].y_org + ((info[i].height - mh) / 2);
|
||||||
|
XFree(info);
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
@@ -634,11 +644,10 @@ setup(void)
|
||||||
|
if (!XGetWindowAttributes(dpy, parentwin, &wa))
|
||||||
|
die("could not get embedding window attributes: 0x%lx",
|
||||||
|
parentwin);
|
||||||
|
- x = 0;
|
||||||
|
- y = topbar ? 0 : wa.height - mh;
|
||||||
|
- mw = wa.width;
|
||||||
|
+ mw = MIN(MAX(max_textw() + promptw, 100), wa.width);
|
||||||
|
+ x = (wa.width - mw) / 2;
|
||||||
|
+ y = (wa.height - mh) / 2;
|
||||||
|
}
|
||||||
|
- promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0;
|
||||||
|
inputw = MIN(inputw, mw/3);
|
||||||
|
match();
|
||||||
|
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
From 39ab9676914bd0d8105d0f96bbd7611a53077438 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Miles Alan <m@milesalan.com>
|
||||||
|
Date: Sat, 4 Jul 2020 11:19:04 -0500
|
||||||
|
Subject: [PATCH] Add -g option to display entries in the given number of grid
|
||||||
|
columns
|
||||||
|
|
||||||
|
This option can be used in conjunction with -l to format dmenu's options in
|
||||||
|
arbitrary size grids. For example, to create a 4 column by 6 line grid, you
|
||||||
|
could use: dmenu -g 4 -l 6
|
||||||
|
---
|
||||||
|
config.def.h | 3 ++-
|
||||||
|
dmenu.1 | 7 ++++++-
|
||||||
|
dmenu.c | 22 ++++++++++++++++------
|
||||||
|
3 files changed, 24 insertions(+), 8 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/config.def.h b/config.def.h
|
||||||
|
index 1edb647..96cf3c9 100644
|
||||||
|
--- a/config.def.h
|
||||||
|
+++ b/config.def.h
|
||||||
|
@@ -13,8 +13,9 @@ static const char *colors[SchemeLast][2] = {
|
||||||
|
[SchemeSel] = { "#eeeeee", "#005577" },
|
||||||
|
[SchemeOut] = { "#000000", "#00ffff" },
|
||||||
|
};
|
||||||
|
-/* -l option; if nonzero, dmenu uses vertical list with given number of lines */
|
||||||
|
+/* -l and -g options; controls number of lines and columns in grid if > 0 */
|
||||||
|
static unsigned int lines = 0;
|
||||||
|
+static unsigned int columns = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Characters not considered part of a word while deleting words
|
||||||
|
diff --git a/dmenu.1 b/dmenu.1
|
||||||
|
index 323f93c..d0a734a 100644
|
||||||
|
--- a/dmenu.1
|
||||||
|
+++ b/dmenu.1
|
||||||
|
@@ -4,6 +4,8 @@ dmenu \- dynamic menu
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B dmenu
|
||||||
|
.RB [ \-bfiv ]
|
||||||
|
+.RB [ \-g
|
||||||
|
+.IR columns ]
|
||||||
|
.RB [ \-l
|
||||||
|
.IR lines ]
|
||||||
|
.RB [ \-m
|
||||||
|
@@ -47,8 +49,11 @@ is faster, but will lock up X until stdin reaches end\-of\-file.
|
||||||
|
.B \-i
|
||||||
|
dmenu matches menu items case insensitively.
|
||||||
|
.TP
|
||||||
|
+.BI \-g " columns"
|
||||||
|
+dmenu lists items in a grid with the given number of columns.
|
||||||
|
+.TP
|
||||||
|
.BI \-l " lines"
|
||||||
|
-dmenu lists items vertically, with the given number of lines.
|
||||||
|
+dmenu lists items in a grid with the given number of lines.
|
||||||
|
.TP
|
||||||
|
.BI \-m " monitor"
|
||||||
|
dmenu is displayed on the monitor number supplied. Monitor numbers are starting
|
||||||
|
diff --git a/dmenu.c b/dmenu.c
|
||||||
|
index 6b8f51b..d79b6bb 100644
|
||||||
|
--- a/dmenu.c
|
||||||
|
+++ b/dmenu.c
|
||||||
|
@@ -77,7 +77,7 @@ calcoffsets(void)
|
||||||
|
int i, n;
|
||||||
|
|
||||||
|
if (lines > 0)
|
||||||
|
- n = lines * bh;
|
||||||
|
+ n = lines * columns * bh;
|
||||||
|
else
|
||||||
|
n = mw - (promptw + inputw + TEXTW("<") + TEXTW(">"));
|
||||||
|
/* calculate which items will begin the next page and previous page */
|
||||||
|
@@ -152,9 +152,15 @@ drawmenu(void)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lines > 0) {
|
||||||
|
- /* draw vertical list */
|
||||||
|
- for (item = curr; item != next; item = item->right)
|
||||||
|
- drawitem(item, x, y += bh, mw - x);
|
||||||
|
+ /* draw grid */
|
||||||
|
+ int i = 0;
|
||||||
|
+ for (item = curr; item != next; item = item->right, i++)
|
||||||
|
+ drawitem(
|
||||||
|
+ item,
|
||||||
|
+ x + ((i / lines) * ((mw - x) / columns)),
|
||||||
|
+ y + (((i % lines) + 1) * bh),
|
||||||
|
+ (mw - x) / columns
|
||||||
|
+ );
|
||||||
|
} else if (matches) {
|
||||||
|
/* draw horizontal list */
|
||||||
|
x += inputw;
|
||||||
|
@@ -708,9 +714,13 @@ main(int argc, char *argv[])
|
||||||
|
} else if (i + 1 == argc)
|
||||||
|
usage();
|
||||||
|
/* these options take one argument */
|
||||||
|
- else if (!strcmp(argv[i], "-l")) /* number of lines in vertical list */
|
||||||
|
+ else if (!strcmp(argv[i], "-g")) { /* number of columns in grid */
|
||||||
|
+ columns = atoi(argv[++i]);
|
||||||
|
+ if (lines == 0) lines = 1;
|
||||||
|
+ } else if (!strcmp(argv[i], "-l")) { /* number of lines in grid */
|
||||||
|
lines = atoi(argv[++i]);
|
||||||
|
- else if (!strcmp(argv[i], "-m"))
|
||||||
|
+ if (columns == 0) columns = 1;
|
||||||
|
+ } else if (!strcmp(argv[i], "-m"))
|
||||||
|
mon = atoi(argv[++i]);
|
||||||
|
else if (!strcmp(argv[i], "-p")) /* adds prompt to left of input field */
|
||||||
|
prompt = argv[++i];
|
||||||
|
--
|
||||||
|
2.23.1
|
||||||
|
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
.TH STEST 1 dmenu\-VERSION
|
||||||
|
.SH NAME
|
||||||
|
stest \- filter a list of files by properties
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B stest
|
||||||
|
.RB [ -abcdefghlpqrsuwx ]
|
||||||
|
.RB [ -n
|
||||||
|
.IR file ]
|
||||||
|
.RB [ -o
|
||||||
|
.IR file ]
|
||||||
|
.RI [ file ...]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.B stest
|
||||||
|
takes a list of files and filters by the files' properties, analogous to
|
||||||
|
.IR test (1).
|
||||||
|
Files which pass all tests are printed to stdout. If no files are given, stest
|
||||||
|
reads files from stdin.
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
.B \-a
|
||||||
|
Test hidden files.
|
||||||
|
.TP
|
||||||
|
.B \-b
|
||||||
|
Test that files are block specials.
|
||||||
|
.TP
|
||||||
|
.B \-c
|
||||||
|
Test that files are character specials.
|
||||||
|
.TP
|
||||||
|
.B \-d
|
||||||
|
Test that files are directories.
|
||||||
|
.TP
|
||||||
|
.B \-e
|
||||||
|
Test that files exist.
|
||||||
|
.TP
|
||||||
|
.B \-f
|
||||||
|
Test that files are regular files.
|
||||||
|
.TP
|
||||||
|
.B \-g
|
||||||
|
Test that files have their set-group-ID flag set.
|
||||||
|
.TP
|
||||||
|
.B \-h
|
||||||
|
Test that files are symbolic links.
|
||||||
|
.TP
|
||||||
|
.B \-l
|
||||||
|
Test the contents of a directory given as an argument.
|
||||||
|
.TP
|
||||||
|
.BI \-n " file"
|
||||||
|
Test that files are newer than
|
||||||
|
.IR file .
|
||||||
|
.TP
|
||||||
|
.BI \-o " file"
|
||||||
|
Test that files are older than
|
||||||
|
.IR file .
|
||||||
|
.TP
|
||||||
|
.B \-p
|
||||||
|
Test that files are named pipes.
|
||||||
|
.TP
|
||||||
|
.B \-q
|
||||||
|
No files are printed, only the exit status is returned.
|
||||||
|
.TP
|
||||||
|
.B \-r
|
||||||
|
Test that files are readable.
|
||||||
|
.TP
|
||||||
|
.B \-s
|
||||||
|
Test that files are not empty.
|
||||||
|
.TP
|
||||||
|
.B \-u
|
||||||
|
Test that files have their set-user-ID flag set.
|
||||||
|
.TP
|
||||||
|
.B \-v
|
||||||
|
Invert the sense of tests, only failing files pass.
|
||||||
|
.TP
|
||||||
|
.B \-w
|
||||||
|
Test that files are writable.
|
||||||
|
.TP
|
||||||
|
.B \-x
|
||||||
|
Test that files are executable.
|
||||||
|
.SH EXIT STATUS
|
||||||
|
.TP
|
||||||
|
.B 0
|
||||||
|
At least one file passed all tests.
|
||||||
|
.TP
|
||||||
|
.B 1
|
||||||
|
No files passed all tests.
|
||||||
|
.TP
|
||||||
|
.B 2
|
||||||
|
An error occurred.
|
||||||
|
.SH SEE ALSO
|
||||||
|
.IR dmenu (1),
|
||||||
|
.IR test (1)
|
||||||
+109
@@ -0,0 +1,109 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "arg.h"
|
||||||
|
char *argv0;
|
||||||
|
|
||||||
|
#define FLAG(x) (flag[(x)-'a'])
|
||||||
|
|
||||||
|
static void test(const char *, const char *);
|
||||||
|
static void usage(void);
|
||||||
|
|
||||||
|
static int match = 0;
|
||||||
|
static int flag[26];
|
||||||
|
static struct stat old, new;
|
||||||
|
|
||||||
|
static void
|
||||||
|
test(const char *path, const char *name)
|
||||||
|
{
|
||||||
|
struct stat st, ln;
|
||||||
|
|
||||||
|
if ((!stat(path, &st) && (FLAG('a') || name[0] != '.') /* hidden files */
|
||||||
|
&& (!FLAG('b') || S_ISBLK(st.st_mode)) /* block special */
|
||||||
|
&& (!FLAG('c') || S_ISCHR(st.st_mode)) /* character special */
|
||||||
|
&& (!FLAG('d') || S_ISDIR(st.st_mode)) /* directory */
|
||||||
|
&& (!FLAG('e') || access(path, F_OK) == 0) /* exists */
|
||||||
|
&& (!FLAG('f') || S_ISREG(st.st_mode)) /* regular file */
|
||||||
|
&& (!FLAG('g') || st.st_mode & S_ISGID) /* set-group-id flag */
|
||||||
|
&& (!FLAG('h') || (!lstat(path, &ln) && S_ISLNK(ln.st_mode))) /* symbolic link */
|
||||||
|
&& (!FLAG('n') || st.st_mtime > new.st_mtime) /* newer than file */
|
||||||
|
&& (!FLAG('o') || st.st_mtime < old.st_mtime) /* older than file */
|
||||||
|
&& (!FLAG('p') || S_ISFIFO(st.st_mode)) /* named pipe */
|
||||||
|
&& (!FLAG('r') || access(path, R_OK) == 0) /* readable */
|
||||||
|
&& (!FLAG('s') || st.st_size > 0) /* not empty */
|
||||||
|
&& (!FLAG('u') || st.st_mode & S_ISUID) /* set-user-id flag */
|
||||||
|
&& (!FLAG('w') || access(path, W_OK) == 0) /* writable */
|
||||||
|
&& (!FLAG('x') || access(path, X_OK) == 0)) != FLAG('v')) { /* executable */
|
||||||
|
if (FLAG('q'))
|
||||||
|
exit(0);
|
||||||
|
match = 1;
|
||||||
|
puts(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "usage: %s [-abcdefghlpqrsuvwx] "
|
||||||
|
"[-n file] [-o file] [file...]\n", argv0);
|
||||||
|
exit(2); /* like test(1) return > 1 on error */
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
struct dirent *d;
|
||||||
|
char path[PATH_MAX], *line = NULL, *file;
|
||||||
|
size_t linesiz = 0;
|
||||||
|
ssize_t n;
|
||||||
|
DIR *dir;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
ARGBEGIN {
|
||||||
|
case 'n': /* newer than file */
|
||||||
|
case 'o': /* older than file */
|
||||||
|
file = EARGF(usage());
|
||||||
|
if (!(FLAG(ARGC()) = !stat(file, (ARGC() == 'n' ? &new : &old))))
|
||||||
|
perror(file);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* miscellaneous operators */
|
||||||
|
if (strchr("abcdefghlpqrsuvwx", ARGC()))
|
||||||
|
FLAG(ARGC()) = 1;
|
||||||
|
else
|
||||||
|
usage(); /* unknown flag */
|
||||||
|
} ARGEND;
|
||||||
|
|
||||||
|
if (!argc) {
|
||||||
|
/* read list from stdin */
|
||||||
|
while ((n = getline(&line, &linesiz, stdin)) > 0) {
|
||||||
|
if (line[n - 1] == '\n')
|
||||||
|
line[n - 1] = '\0';
|
||||||
|
test(line, line);
|
||||||
|
}
|
||||||
|
free(line);
|
||||||
|
} else {
|
||||||
|
for (; argc; argc--, argv++) {
|
||||||
|
if (FLAG('l') && (dir = opendir(*argv))) {
|
||||||
|
/* test directory contents */
|
||||||
|
while ((d = readdir(dir))) {
|
||||||
|
r = snprintf(path, sizeof path, "%s/%s",
|
||||||
|
*argv, d->d_name);
|
||||||
|
if (r >= 0 && (size_t)r < sizeof path)
|
||||||
|
test(path, d->d_name);
|
||||||
|
}
|
||||||
|
closedir(dir);
|
||||||
|
} else {
|
||||||
|
test(*argv, *argv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return match ? 0 : 1;
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
void *
|
||||||
|
ecalloc(size_t nmemb, size_t size)
|
||||||
|
{
|
||||||
|
void *p;
|
||||||
|
|
||||||
|
if (!(p = calloc(nmemb, size)))
|
||||||
|
die("calloc:");
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
die(const char *fmt, ...) {
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vfprintf(stderr, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
if (fmt[0] && fmt[strlen(fmt)-1] == ':') {
|
||||||
|
fputc(' ', stderr);
|
||||||
|
perror(NULL);
|
||||||
|
} else {
|
||||||
|
fputc('\n', stderr);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
|
||||||
|
#define MAX(A, B) ((A) > (B) ? (A) : (B))
|
||||||
|
#define MIN(A, B) ((A) < (B) ? (A) : (B))
|
||||||
|
#define BETWEEN(X, A, B) ((A) <= (X) && (X) <= (B))
|
||||||
|
|
||||||
|
void die(const char *fmt, ...);
|
||||||
|
void *ecalloc(size_t nmemb, size_t size);
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
*.o
|
||||||
|
*.orig
|
||||||
|
*.rej
|
||||||
|
larbs.pdf
|
||||||
|
dwm
|
||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
sudo make clean install
|
||||||
+37
@@ -0,0 +1,37 @@
|
|||||||
|
MIT/X Consortium License
|
||||||
|
|
||||||
|
© 2006-2019 Anselm R Garbe <anselm@garbe.ca>
|
||||||
|
© 2006-2009 Jukka Salmi <jukka at salmi dot ch>
|
||||||
|
© 2006-2007 Sander van Dijk <a dot h dot vandijk at gmail dot com>
|
||||||
|
© 2007-2011 Peter Hartlich <sgkkr at hartlich dot com>
|
||||||
|
© 2007-2009 Szabolcs Nagy <nszabolcs at gmail dot com>
|
||||||
|
© 2007-2009 Christof Musik <christof at sendfax dot de>
|
||||||
|
© 2007-2009 Premysl Hruby <dfenze at gmail dot com>
|
||||||
|
© 2007-2008 Enno Gottox Boland <gottox at s01 dot de>
|
||||||
|
© 2008 Martin Hurton <martin dot hurton at gmail dot com>
|
||||||
|
© 2008 Neale Pickett <neale dot woozle dot org>
|
||||||
|
© 2009 Mate Nagy <mnagy at port70 dot net>
|
||||||
|
© 2010-2016 Hiltjo Posthuma <hiltjo@codemadness.org>
|
||||||
|
© 2010-2012 Connor Lane Smith <cls@lubutu.com>
|
||||||
|
© 2011 Christoph Lohmann <20h@r-36.net>
|
||||||
|
© 2015-2016 Quentin Rameau <quinq@fifth.space>
|
||||||
|
© 2015-2016 Eric Pruitt <eric.pruitt@gmail.com>
|
||||||
|
© 2016-2017 Markus Teich <markus.teich@stusta.mhn.de>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
copy of this software and associated documentation files (the "Software"),
|
||||||
|
to deal in the Software without restriction, including without limitation
|
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
# dwm - dynamic window manager
|
||||||
|
# See LICENSE file for copyright and license details.
|
||||||
|
|
||||||
|
include config.mk
|
||||||
|
|
||||||
|
SRC = drw.c dwm.c util.c
|
||||||
|
OBJ = ${SRC:.c=.o}
|
||||||
|
|
||||||
|
all: options dwm
|
||||||
|
|
||||||
|
options:
|
||||||
|
@echo dwm build options:
|
||||||
|
@echo "CFLAGS = ${CFLAGS}"
|
||||||
|
@echo "LDFLAGS = ${LDFLAGS}"
|
||||||
|
@echo "CC = ${CC}"
|
||||||
|
|
||||||
|
.c.o:
|
||||||
|
${CC} -c ${CFLAGS} $<
|
||||||
|
|
||||||
|
${OBJ}: config.h config.mk
|
||||||
|
|
||||||
|
config.h:
|
||||||
|
cp config.def.h $@
|
||||||
|
|
||||||
|
dwm: ${OBJ}
|
||||||
|
${CC} -o $@ ${OBJ} ${LDFLAGS}
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f dwm ${OBJ} dwm-${VERSION}.tar.gz
|
||||||
|
|
||||||
|
dist: clean
|
||||||
|
mkdir -p dwm-${VERSION}
|
||||||
|
cp -R LICENSE Makefile README config.def.h config.mk\
|
||||||
|
dwm.1 drw.h util.h ${SRC} dwm.png transient.c dwm-${VERSION}
|
||||||
|
tar -cf dwm-${VERSION}.tar dwm-${VERSION}
|
||||||
|
gzip dwm-${VERSION}.tar
|
||||||
|
rm -rf dwm-${VERSION}
|
||||||
|
|
||||||
|
install: all
|
||||||
|
mkdir -p ${DESTDIR}${PREFIX}/bin
|
||||||
|
cp -f dwm ${DESTDIR}${PREFIX}/bin
|
||||||
|
chmod 755 ${DESTDIR}${PREFIX}/bin/dwm
|
||||||
|
mkdir -p ${DESTDIR}${MANPREFIX}/man1
|
||||||
|
sed "s/VERSION/${VERSION}/g" < dwm.1 > ${DESTDIR}${MANPREFIX}/man1/dwm.1
|
||||||
|
chmod 644 ${DESTDIR}${MANPREFIX}/man1/dwm.1
|
||||||
|
|
||||||
|
uninstall:
|
||||||
|
rm -f ${DESTDIR}${PREFIX}/bin/dwm\
|
||||||
|
${DESTDIR}${MANPREFIX}/man1/dwm.1
|
||||||
|
|
||||||
|
.PHONY: all options clean dist install uninstall
|
||||||
+48
@@ -0,0 +1,48 @@
|
|||||||
|
dwm - dynamic window manager
|
||||||
|
============================
|
||||||
|
dwm is an extremely fast, small, and dynamic window manager for X.
|
||||||
|
|
||||||
|
|
||||||
|
Requirements
|
||||||
|
------------
|
||||||
|
In order to build dwm you need the Xlib header files.
|
||||||
|
|
||||||
|
|
||||||
|
Installation
|
||||||
|
------------
|
||||||
|
Edit config.mk to match your local setup (dwm is installed into
|
||||||
|
the /usr/local namespace by default).
|
||||||
|
|
||||||
|
Afterwards enter the following command to build and install dwm (if
|
||||||
|
necessary as root):
|
||||||
|
|
||||||
|
make clean install
|
||||||
|
|
||||||
|
|
||||||
|
Running dwm
|
||||||
|
-----------
|
||||||
|
Add the following line to your .xinitrc to start dwm using startx:
|
||||||
|
|
||||||
|
exec dwm
|
||||||
|
|
||||||
|
In order to connect dwm to a specific display, make sure that
|
||||||
|
the DISPLAY environment variable is set correctly, e.g.:
|
||||||
|
|
||||||
|
DISPLAY=foo.bar:1 exec dwm
|
||||||
|
|
||||||
|
(This will start dwm on display :1 of the host foo.bar.)
|
||||||
|
|
||||||
|
In order to display status info in the bar, you can do something
|
||||||
|
like this in your .xinitrc:
|
||||||
|
|
||||||
|
while xsetroot -name "`date` `uptime | sed 's/.*,//'`"
|
||||||
|
do
|
||||||
|
sleep 1
|
||||||
|
done &
|
||||||
|
exec dwm
|
||||||
|
|
||||||
|
|
||||||
|
Configuration
|
||||||
|
-------------
|
||||||
|
The configuration of dwm is done by creating a custom config.h
|
||||||
|
and (re)compiling the source code.
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
# Caleb's Fork of dwm
|
||||||
|
|
||||||
|
dwm - dynamic window manager
|
||||||
|
============================
|
||||||
|
dwm is an extremely fast, small, and dynamic window manager for X.
|
||||||
|
|
||||||
|
|
||||||
|
Requirements
|
||||||
|
------------
|
||||||
|
In order to build dwm you need the Xlib header files.
|
||||||
|
|
||||||
|
|
||||||
|
Installation
|
||||||
|
------------
|
||||||
|
Edit config.mk to match your local setup (dwm is installed into
|
||||||
|
the /usr/local namespace by default).
|
||||||
|
|
||||||
|
Afterwards enter the following command to build and install dwm (if
|
||||||
|
necessary as root):
|
||||||
|
|
||||||
|
make clean install
|
||||||
|
|
||||||
|
|
||||||
|
Running dwm
|
||||||
|
-----------
|
||||||
|
Add the following line to your .xinitrc to start dwm using startx:
|
||||||
|
|
||||||
|
exec dwm
|
||||||
|
|
||||||
|
In order to connect dwm to a specific display, make sure that
|
||||||
|
the DISPLAY environment variable is set correctly, e.g.:
|
||||||
|
|
||||||
|
DISPLAY=foo.bar:1 exec dwm
|
||||||
|
|
||||||
|
(This will start dwm on display :1 of the host foo.bar.)
|
||||||
|
|
||||||
|
In order to display status info in the bar, you can do something
|
||||||
|
like this in your .xinitrc:
|
||||||
|
|
||||||
|
while xsetroot -name "`date` `uptime | sed 's/.*,//'`"
|
||||||
|
do
|
||||||
|
sleep 1
|
||||||
|
done &
|
||||||
|
exec dwm
|
||||||
|
|
||||||
|
|
||||||
|
Configuration
|
||||||
|
-------------
|
||||||
|
The configuration of dwm is done by creating a custom config.h
|
||||||
|
and (re)compiling the source code.
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
|
||||||
|
/* appearance */
|
||||||
|
static const unsigned int borderpx = 1; /* border pixel of windows */
|
||||||
|
static const unsigned int snap = 32; /* snap pixel */
|
||||||
|
static const int showbar = 1; /* 0 means no bar */
|
||||||
|
static const int topbar = 1; /* 0 means bottom bar */
|
||||||
|
static const char *fonts[] = { "monospace:size=10" };
|
||||||
|
static const char dmenufont[] = "monospace:size=10";
|
||||||
|
static const char col_gray1[] = "#222222";
|
||||||
|
static const char col_gray2[] = "#444444";
|
||||||
|
static const char col_gray3[] = "#bbbbbb";
|
||||||
|
static const char col_gray4[] = "#eeeeee";
|
||||||
|
static const char col_cyan[] = "#005577";
|
||||||
|
static const char *colors[][3] = {
|
||||||
|
/* fg bg border */
|
||||||
|
[SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
|
||||||
|
[SchemeSel] = { col_gray4, col_cyan, col_cyan },
|
||||||
|
};
|
||||||
|
|
||||||
|
/* tagging */
|
||||||
|
static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
|
||||||
|
|
||||||
|
static const Rule rules[] = {
|
||||||
|
/* xprop(1):
|
||||||
|
* WM_CLASS(STRING) = instance, class
|
||||||
|
* WM_NAME(STRING) = title
|
||||||
|
*/
|
||||||
|
/* class instance title tags mask isfloating monitor */
|
||||||
|
{ "Gimp", NULL, NULL, 0, 1, -1 },
|
||||||
|
{ "Firefox", NULL, NULL, 1 << 8, 0, -1 },
|
||||||
|
};
|
||||||
|
|
||||||
|
/* layout(s) */
|
||||||
|
static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */
|
||||||
|
static const int nmaster = 1; /* number of clients in master area */
|
||||||
|
static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */
|
||||||
|
static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */
|
||||||
|
|
||||||
|
static const Layout layouts[] = {
|
||||||
|
/* symbol arrange function */
|
||||||
|
{ "[]=", tile }, /* first entry is default */
|
||||||
|
{ "><>", NULL }, /* no layout function means floating behavior */
|
||||||
|
{ "[M]", monocle },
|
||||||
|
};
|
||||||
|
|
||||||
|
/* key definitions */
|
||||||
|
#define MODKEY Mod1Mask
|
||||||
|
#define TAGKEYS(KEY,TAG) \
|
||||||
|
{ MODKEY, KEY, view, {.ui = 1 << TAG} }, \
|
||||||
|
{ MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \
|
||||||
|
{ MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \
|
||||||
|
{ MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} },
|
||||||
|
|
||||||
|
/* helper for spawning shell commands in the pre dwm-5.0 fashion */
|
||||||
|
#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
|
||||||
|
|
||||||
|
/* commands */
|
||||||
|
static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */
|
||||||
|
static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
|
||||||
|
static const char *termcmd[] = { "st", NULL };
|
||||||
|
|
||||||
|
static Key keys[] = {
|
||||||
|
/* modifier key function argument */
|
||||||
|
{ MODKEY, XK_p, spawn, {.v = dmenucmd } },
|
||||||
|
{ MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
|
||||||
|
{ MODKEY, XK_b, togglebar, {0} },
|
||||||
|
{ MODKEY, XK_j, focusstack, {.i = +1 } },
|
||||||
|
{ MODKEY, XK_k, focusstack, {.i = -1 } },
|
||||||
|
{ MODKEY, XK_i, incnmaster, {.i = +1 } },
|
||||||
|
{ MODKEY, XK_d, incnmaster, {.i = -1 } },
|
||||||
|
{ MODKEY, XK_h, setmfact, {.f = -0.05} },
|
||||||
|
{ MODKEY, XK_l, setmfact, {.f = +0.05} },
|
||||||
|
{ MODKEY, XK_Return, zoom, {0} },
|
||||||
|
{ MODKEY, XK_Tab, view, {0} },
|
||||||
|
{ MODKEY|ShiftMask, XK_c, killclient, {0} },
|
||||||
|
{ MODKEY, XK_t, setlayout, {.v = &layouts[0]} },
|
||||||
|
{ MODKEY, XK_f, setlayout, {.v = &layouts[1]} },
|
||||||
|
{ MODKEY, XK_m, setlayout, {.v = &layouts[2]} },
|
||||||
|
{ MODKEY, XK_space, setlayout, {0} },
|
||||||
|
{ MODKEY|ShiftMask, XK_space, togglefloating, {0} },
|
||||||
|
{ MODKEY, XK_0, view, {.ui = ~0 } },
|
||||||
|
{ MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } },
|
||||||
|
{ MODKEY, XK_comma, focusmon, {.i = -1 } },
|
||||||
|
{ MODKEY, XK_period, focusmon, {.i = +1 } },
|
||||||
|
{ MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } },
|
||||||
|
{ MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } },
|
||||||
|
TAGKEYS( XK_1, 0)
|
||||||
|
TAGKEYS( XK_2, 1)
|
||||||
|
TAGKEYS( XK_3, 2)
|
||||||
|
TAGKEYS( XK_4, 3)
|
||||||
|
TAGKEYS( XK_5, 4)
|
||||||
|
TAGKEYS( XK_6, 5)
|
||||||
|
TAGKEYS( XK_7, 6)
|
||||||
|
TAGKEYS( XK_8, 7)
|
||||||
|
TAGKEYS( XK_9, 8)
|
||||||
|
{ MODKEY|ShiftMask, XK_q, quit, {0} },
|
||||||
|
};
|
||||||
|
|
||||||
|
/* button definitions */
|
||||||
|
/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */
|
||||||
|
static Button buttons[] = {
|
||||||
|
/* click event mask button function argument */
|
||||||
|
{ ClkLtSymbol, 0, Button1, setlayout, {0} },
|
||||||
|
{ ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} },
|
||||||
|
{ ClkWinTitle, 0, Button2, zoom, {0} },
|
||||||
|
{ ClkStatusText, 0, Button2, spawn, {.v = termcmd } },
|
||||||
|
{ ClkClientWin, MODKEY, Button1, movemouse, {0} },
|
||||||
|
{ ClkClientWin, MODKEY, Button2, togglefloating, {0} },
|
||||||
|
{ ClkClientWin, MODKEY, Button3, resizemouse, {0} },
|
||||||
|
{ ClkTagBar, 0, Button1, view, {0} },
|
||||||
|
{ ClkTagBar, 0, Button3, toggleview, {0} },
|
||||||
|
{ ClkTagBar, MODKEY, Button1, tag, {0} },
|
||||||
|
{ ClkTagBar, MODKEY, Button3, toggletag, {0} },
|
||||||
|
};
|
||||||
|
|
||||||
+162
@@ -0,0 +1,162 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <X11/XF86keysym.h>
|
||||||
|
|
||||||
|
#include <X11/keysymdef.h>
|
||||||
|
#define XK_MISCELLANY
|
||||||
|
|
||||||
|
/* appearance */
|
||||||
|
static const unsigned int borderpx = 3; /* border pixel of windows */
|
||||||
|
static const unsigned int gappx = 8; /* gap pixel between windows */
|
||||||
|
static const unsigned int snap = 32; /* snap pixel */
|
||||||
|
static const int showbar = 1; /* 0 means no bar */
|
||||||
|
static const int topbar = 1; /* 0 means bottom bar */
|
||||||
|
static const char *fonts[] = { "monospace:size=16", "BitstreamVeraSansMono Nerd Font:pixelsize=25", "JoyPixels:pixelsize=16"};
|
||||||
|
static const char dmenufont[] = "monospace:size=16";
|
||||||
|
static const char col_gray1[] = "#222222";
|
||||||
|
static const char col_gray2[] = "#444444";
|
||||||
|
static const char col_gray3[] = "#bbbbbb";
|
||||||
|
static const char col_gray4[] = "#eeeeee";
|
||||||
|
static const char col_cyan[] = "#005577";
|
||||||
|
static const char *colors[][3] = {
|
||||||
|
/* fg bg border */
|
||||||
|
[SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
|
||||||
|
[SchemeSel] = { col_gray4, col_cyan, col_cyan },
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Start of alpha status bar patch
|
||||||
|
* https://dwm.suckless.org/patches/alpha/dwm-alpha-20230401-348f655.diff
|
||||||
|
*/
|
||||||
|
static const unsigned int baralpha = 0xd0;
|
||||||
|
static const unsigned int borderalpha = OPAQUE;
|
||||||
|
static const unsigned int alphas[][3] = {
|
||||||
|
/* fg bg border*/
|
||||||
|
[SchemeNorm] = { OPAQUE, baralpha, borderalpha },
|
||||||
|
[SchemeSel] = { OPAQUE, baralpha, borderalpha },
|
||||||
|
};
|
||||||
|
|
||||||
|
/* audio constants */
|
||||||
|
static const char *upvol[] = { "amixer", "set", "Master", "2%+", NULL};
|
||||||
|
static const char *downvol[] = { "amixer", "set", "Master", "2%-", NULL};
|
||||||
|
static const char *mutevol[] = { "amixer", "set", "Master", "toggle", NULL};
|
||||||
|
|
||||||
|
/* brightness constants */
|
||||||
|
static const char *upbrightness[] = {"/home/caleb/.local/bin/brightness_up", NULL};
|
||||||
|
static const char *downbrightness[] = {"/home/caleb/.local/bin/brightness_down", NULL};
|
||||||
|
|
||||||
|
/* toggle emoji menu */
|
||||||
|
static const char *emojimenu[] = {"/home/caleb/.local/bin/dmenuunicode", NULL};
|
||||||
|
|
||||||
|
/* tagging */
|
||||||
|
static const char *tags[] = { "0", "1", "2", "3", "4", "5" };
|
||||||
|
|
||||||
|
static const Rule rules[] = {
|
||||||
|
/* xprop(1):
|
||||||
|
* WM_CLASS(STRING) = instance, class
|
||||||
|
* WM_NAME(STRING) = title
|
||||||
|
*/
|
||||||
|
/* class instance title tags mask isfloating monitor */
|
||||||
|
{ "Gimp", NULL, NULL, 0, 1, -1 },
|
||||||
|
{ "Firefox", NULL, NULL, 1 << 8, 0, -1 },
|
||||||
|
};
|
||||||
|
|
||||||
|
/* layout(s) */
|
||||||
|
static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */
|
||||||
|
static const int nmaster = 1; /* number of clients in master area */
|
||||||
|
static const int resizehints = 0; /* 1 means respect size hints in tiled resizals */
|
||||||
|
static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */
|
||||||
|
|
||||||
|
static const Layout layouts[] = {
|
||||||
|
/* symbol arrange function */
|
||||||
|
{ "[]=", tile }, /* first entry is default */
|
||||||
|
{ "><>", NULL }, /* no layout function means floating behavior */
|
||||||
|
{ "[M]", monocle },
|
||||||
|
};
|
||||||
|
|
||||||
|
/* key definitions */
|
||||||
|
#define TABKEY XK_Tab
|
||||||
|
#define ALTKEY Mod1Mask
|
||||||
|
#define SUPERKEY Mod4Mask // aka windows key
|
||||||
|
#define MODKEY SUPERKEY
|
||||||
|
#define TAGKEYS(KEY,TAG) \
|
||||||
|
{ MODKEY, KEY, view, {.ui = 1 << TAG} }, \
|
||||||
|
{ MODKEY|ControlMask, KEY, toggleview, {.ui = 1 << TAG} }, \
|
||||||
|
{ MODKEY|ShiftMask, KEY, tag, {.ui = 1 << TAG} }, \
|
||||||
|
{ MODKEY|ControlMask|ShiftMask, KEY, toggletag, {.ui = 1 << TAG} },
|
||||||
|
|
||||||
|
/* helper for spawning shell commands in the pre dwm-5.0 fashion */
|
||||||
|
#define SHCMD(cmd) { .v = (const char*[]){ "/usr/local/bin/st", "-c", cmd, NULL } }
|
||||||
|
|
||||||
|
/* commands */
|
||||||
|
static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */
|
||||||
|
static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
|
||||||
|
static const char *termcmd[] = { "st", NULL };
|
||||||
|
static const char *print_screen_cmd[] = { "flameshot", "gui", NULL };
|
||||||
|
static const char *google_cmd[] = { "google-chrome-stable", NULL };
|
||||||
|
|
||||||
|
#include "shiftview.c"
|
||||||
|
|
||||||
|
static Key keys[] = {
|
||||||
|
/* modifier key function argument */
|
||||||
|
{ MODKEY, XK_p, spawn, {.v = dmenucmd } },
|
||||||
|
{ MODKEY|ShiftMask, XK_Return, spawn, {.v = termcmd } },
|
||||||
|
{ MODKEY, XK_b, togglebar, {0} },
|
||||||
|
{ MODKEY, XK_j, focusstack, {.i = +1 } },
|
||||||
|
{ MODKEY, XK_k, focusstack, {.i = -1 } },
|
||||||
|
{ MODKEY, XK_i, incnmaster, {.i = +1 } },
|
||||||
|
{ MODKEY, XK_d, incnmaster, {.i = -1 } },
|
||||||
|
{ MODKEY, XK_h, setmfact, {.f = -0.05} },
|
||||||
|
{ MODKEY, XK_l, setmfact, {.f = +0.05} },
|
||||||
|
{ MODKEY, XK_Return, zoom, {0} },
|
||||||
|
{ MODKEY, XK_Tab, shiftview, { 1 } },
|
||||||
|
{ MODKEY|ShiftMask, XK_Tab, shiftview, { -1 } },
|
||||||
|
{ MODKEY|ShiftMask, XK_c, killclient, {0} },
|
||||||
|
{ MODKEY, XK_t, setlayout, {.v = &layouts[0]} },
|
||||||
|
{ MODKEY, XK_f, setlayout, {.v = &layouts[1]} },
|
||||||
|
{ MODKEY, XK_m, setlayout, {.v = &layouts[2]} },
|
||||||
|
{ MODKEY, XK_space, setlayout, {0} },
|
||||||
|
{ MODKEY|ShiftMask, XK_space, togglefloating, {0} },
|
||||||
|
{ MODKEY, XK_0, view, {.ui = ~0 } },
|
||||||
|
{ MODKEY|ShiftMask, XK_0, tag, {.ui = ~0 } },
|
||||||
|
{ MODKEY, XK_comma, focusmon, {.i = -1 } },
|
||||||
|
{ MODKEY, XK_period, focusmon, {.i = +1 } },
|
||||||
|
{ MODKEY|ShiftMask, XK_comma, tagmon, {.i = -1 } },
|
||||||
|
{ MODKEY|ShiftMask, XK_period, tagmon, {.i = +1 } },
|
||||||
|
TAGKEYS( XK_grave, 0)
|
||||||
|
TAGKEYS( XK_1, 1)
|
||||||
|
TAGKEYS( XK_2, 2)
|
||||||
|
TAGKEYS( XK_3, 3)
|
||||||
|
TAGKEYS( XK_4, 4)
|
||||||
|
TAGKEYS( XK_5, 5)
|
||||||
|
TAGKEYS( XK_6, 6)
|
||||||
|
TAGKEYS( XK_7, 7)
|
||||||
|
TAGKEYS( XK_8, 8)
|
||||||
|
TAGKEYS( XK_9, 9)
|
||||||
|
{ MODKEY|ShiftMask, XK_q, quit, {0} },
|
||||||
|
/* User defined keybinds */
|
||||||
|
{ MODKEY, XK_e, spawn, {.v = emojimenu } },
|
||||||
|
{ 0, XK_Print, spawn, {.v = print_screen_cmd } },
|
||||||
|
{ 0, XK_F14, spawn, {.v = google_cmd } },
|
||||||
|
{ 0, XF86XK_MonBrightnessDown, spawn, {.v = downbrightness } },
|
||||||
|
{ 0, XF86XK_MonBrightnessUp, spawn, {.v = upbrightness } },
|
||||||
|
{ 0, XF86XK_AudioLowerVolume, spawn, {.v = downvol } },
|
||||||
|
{ 0, XF86XK_AudioRaiseVolume, spawn, {.v = upvol } },
|
||||||
|
{ 0, XF86XK_AudioMute, spawn, {.v = mutevol } },
|
||||||
|
};
|
||||||
|
|
||||||
|
/* button definitions */
|
||||||
|
/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */
|
||||||
|
static Button buttons[] = {
|
||||||
|
/* click event mask button function argument */
|
||||||
|
{ ClkLtSymbol, 0, Button1, setlayout, {0} },
|
||||||
|
{ ClkLtSymbol, 0, Button3, setlayout, {.v = &layouts[2]} },
|
||||||
|
{ ClkWinTitle, 0, Button2, zoom, {0} },
|
||||||
|
{ ClkStatusText, 0, Button2, spawn, {.v = termcmd } },
|
||||||
|
{ ClkClientWin, MODKEY, Button1, movemouse, {0} },
|
||||||
|
{ ClkClientWin, MODKEY, Button2, togglefloating, {0} },
|
||||||
|
{ ClkClientWin, MODKEY, Button3, resizemouse, {0} },
|
||||||
|
{ ClkTagBar, 0, Button1, view, {0} },
|
||||||
|
{ ClkTagBar, 0, Button3, toggleview, {0} },
|
||||||
|
{ ClkTagBar, MODKEY, Button1, tag, {0} },
|
||||||
|
{ ClkTagBar, MODKEY, Button3, toggletag, {0} },
|
||||||
|
};
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
# dwm version
|
||||||
|
VERSION = 6.2
|
||||||
|
|
||||||
|
# Customize below to fit your system
|
||||||
|
|
||||||
|
# paths
|
||||||
|
PREFIX = /usr/local
|
||||||
|
MANPREFIX = ${PREFIX}/share/man
|
||||||
|
|
||||||
|
X11INC = /usr/X11R6/include
|
||||||
|
X11LIB = /usr/X11R6/lib
|
||||||
|
|
||||||
|
# Xinerama, comment if you don't want it
|
||||||
|
XINERAMALIBS = -lXinerama
|
||||||
|
XINERAMAFLAGS = -DXINERAMA
|
||||||
|
|
||||||
|
# freetype
|
||||||
|
FREETYPELIBS = -lfontconfig -lXft
|
||||||
|
FREETYPEINC = /usr/include/freetype2
|
||||||
|
# OpenBSD (uncomment)
|
||||||
|
#FREETYPEINC = ${X11INC}/freetype2
|
||||||
|
|
||||||
|
# includes and libs
|
||||||
|
INCS = -I${X11INC} -I${FREETYPEINC}
|
||||||
|
LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -lXrender
|
||||||
|
|
||||||
|
# flags
|
||||||
|
CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
|
||||||
|
#CFLAGS = -g -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS}
|
||||||
|
CFLAGS = -std=c99 -pedantic -Wall -Wno-deprecated-declarations -Os ${INCS} ${CPPFLAGS}
|
||||||
|
LDFLAGS = ${LIBS}
|
||||||
|
|
||||||
|
# Solaris
|
||||||
|
#CFLAGS = -fast ${INCS} -DVERSION=\"${VERSION}\"
|
||||||
|
#LDFLAGS = ${LIBS}
|
||||||
|
|
||||||
|
# compiler and linker
|
||||||
|
CC = cc
|
||||||
@@ -0,0 +1,423 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include <X11/Xft/Xft.h>
|
||||||
|
|
||||||
|
#include "drw.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#define UTF_INVALID 0xFFFD
|
||||||
|
#define UTF_SIZ 4
|
||||||
|
|
||||||
|
static const unsigned char utfbyte[UTF_SIZ + 1] = {0x80, 0, 0xC0, 0xE0, 0xF0};
|
||||||
|
static const unsigned char utfmask[UTF_SIZ + 1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
|
||||||
|
static const long utfmin[UTF_SIZ + 1] = { 0, 0, 0x80, 0x800, 0x10000};
|
||||||
|
static const long utfmax[UTF_SIZ + 1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
|
||||||
|
|
||||||
|
static long
|
||||||
|
utf8decodebyte(const char c, size_t *i)
|
||||||
|
{
|
||||||
|
for (*i = 0; *i < (UTF_SIZ + 1); ++(*i))
|
||||||
|
if (((unsigned char)c & utfmask[*i]) == utfbyte[*i])
|
||||||
|
return (unsigned char)c & ~utfmask[*i];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
utf8validate(long *u, size_t i)
|
||||||
|
{
|
||||||
|
if (!BETWEEN(*u, utfmin[i], utfmax[i]) || BETWEEN(*u, 0xD800, 0xDFFF))
|
||||||
|
*u = UTF_INVALID;
|
||||||
|
for (i = 1; *u > utfmax[i]; ++i)
|
||||||
|
;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t
|
||||||
|
utf8decode(const char *c, long *u, size_t clen)
|
||||||
|
{
|
||||||
|
size_t i, j, len, type;
|
||||||
|
long udecoded;
|
||||||
|
|
||||||
|
*u = UTF_INVALID;
|
||||||
|
if (!clen)
|
||||||
|
return 0;
|
||||||
|
udecoded = utf8decodebyte(c[0], &len);
|
||||||
|
if (!BETWEEN(len, 1, UTF_SIZ))
|
||||||
|
return 1;
|
||||||
|
for (i = 1, j = 1; i < clen && j < len; ++i, ++j) {
|
||||||
|
udecoded = (udecoded << 6) | utf8decodebyte(c[i], &type);
|
||||||
|
if (type)
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
if (j < len)
|
||||||
|
return 0;
|
||||||
|
*u = udecoded;
|
||||||
|
utf8validate(u, len);
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
Drw *
|
||||||
|
drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h, Visual *visual, unsigned int depth, Colormap cmap)
|
||||||
|
{
|
||||||
|
Drw *drw = ecalloc(1, sizeof(Drw));
|
||||||
|
|
||||||
|
drw->dpy = dpy;
|
||||||
|
drw->screen = screen;
|
||||||
|
drw->root = root;
|
||||||
|
drw->w = w;
|
||||||
|
drw->h = h;
|
||||||
|
drw->visual = visual;
|
||||||
|
drw->depth = depth;
|
||||||
|
drw->cmap = cmap;
|
||||||
|
drw->drawable = XCreatePixmap(dpy, root, w, h, depth);
|
||||||
|
drw->gc = XCreateGC(dpy, drw->drawable, 0, NULL);
|
||||||
|
XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter);
|
||||||
|
|
||||||
|
return drw;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
drw_resize(Drw *drw, unsigned int w, unsigned int h)
|
||||||
|
{
|
||||||
|
if (!drw)
|
||||||
|
return;
|
||||||
|
|
||||||
|
drw->w = w;
|
||||||
|
drw->h = h;
|
||||||
|
if (drw->drawable)
|
||||||
|
XFreePixmap(drw->dpy, drw->drawable);
|
||||||
|
drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, drw->depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
drw_free(Drw *drw)
|
||||||
|
{
|
||||||
|
XFreePixmap(drw->dpy, drw->drawable);
|
||||||
|
XFreeGC(drw->dpy, drw->gc);
|
||||||
|
drw_fontset_free(drw->fonts);
|
||||||
|
free(drw);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function is an implementation detail. Library users should use
|
||||||
|
* drw_fontset_create instead.
|
||||||
|
*/
|
||||||
|
static Fnt *
|
||||||
|
xfont_create(Drw *drw, const char *fontname, FcPattern *fontpattern)
|
||||||
|
{
|
||||||
|
Fnt *font;
|
||||||
|
XftFont *xfont = NULL;
|
||||||
|
FcPattern *pattern = NULL;
|
||||||
|
|
||||||
|
if (fontname) {
|
||||||
|
/* Using the pattern found at font->xfont->pattern does not yield the
|
||||||
|
* same substitution results as using the pattern returned by
|
||||||
|
* FcNameParse; using the latter results in the desired fallback
|
||||||
|
* behaviour whereas the former just results in missing-character
|
||||||
|
* rectangles being drawn, at least with some fonts. */
|
||||||
|
if (!(xfont = XftFontOpenName(drw->dpy, drw->screen, fontname))) {
|
||||||
|
fprintf(stderr, "error, cannot load font from name: '%s'\n", fontname);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (!(pattern = FcNameParse((FcChar8 *) fontname))) {
|
||||||
|
fprintf(stderr, "error, cannot parse font name to pattern: '%s'\n", fontname);
|
||||||
|
XftFontClose(drw->dpy, xfont);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
} else if (fontpattern) {
|
||||||
|
if (!(xfont = XftFontOpenPattern(drw->dpy, fontpattern))) {
|
||||||
|
fprintf(stderr, "error, cannot load font from pattern.\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
die("no font specified.");
|
||||||
|
}
|
||||||
|
|
||||||
|
font = ecalloc(1, sizeof(Fnt));
|
||||||
|
font->xfont = xfont;
|
||||||
|
font->pattern = pattern;
|
||||||
|
font->h = xfont->ascent + xfont->descent;
|
||||||
|
font->dpy = drw->dpy;
|
||||||
|
|
||||||
|
return font;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
xfont_free(Fnt *font)
|
||||||
|
{
|
||||||
|
if (!font)
|
||||||
|
return;
|
||||||
|
if (font->pattern)
|
||||||
|
FcPatternDestroy(font->pattern);
|
||||||
|
XftFontClose(font->dpy, font->xfont);
|
||||||
|
free(font);
|
||||||
|
}
|
||||||
|
|
||||||
|
Fnt*
|
||||||
|
drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount)
|
||||||
|
{
|
||||||
|
Fnt *cur, *ret = NULL;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if (!drw || !fonts)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for (i = 1; i <= fontcount; i++) {
|
||||||
|
if ((cur = xfont_create(drw, fonts[fontcount - i], NULL))) {
|
||||||
|
cur->next = ret;
|
||||||
|
ret = cur;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (drw->fonts = ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
drw_fontset_free(Fnt *font)
|
||||||
|
{
|
||||||
|
if (font) {
|
||||||
|
drw_fontset_free(font->next);
|
||||||
|
xfont_free(font);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
drw_clr_create(Drw *drw, Clr *dest, const char *clrname, unsigned alpha)
|
||||||
|
{
|
||||||
|
if (!drw || !dest || !clrname)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!XftColorAllocName(drw->dpy, drw->visual, drw->cmap, clrname, dest))
|
||||||
|
die("error, cannot allocate color '%s'", clrname);
|
||||||
|
dest->pixel = (dest->pixel & 0x00ffffffU) | (alpha << 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wrapper to create color schemes. The caller has to call free(3) on the
|
||||||
|
* returned color scheme when done using it. */
|
||||||
|
Clr *
|
||||||
|
drw_scm_create(Drw *drw, const char *clrnames[], const unsigned int alphas[], size_t clrcount)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
Clr *ret;
|
||||||
|
|
||||||
|
/* need at least two colors for a scheme */
|
||||||
|
if (!drw || !clrnames || clrcount < 2 || !(ret = ecalloc(clrcount, sizeof(XftColor))))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for (i = 0; i < clrcount; i++)
|
||||||
|
drw_clr_create(drw, &ret[i], clrnames[i], alphas[i]);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
drw_setfontset(Drw *drw, Fnt *set)
|
||||||
|
{
|
||||||
|
if (drw)
|
||||||
|
drw->fonts = set;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
drw_setscheme(Drw *drw, Clr *scm)
|
||||||
|
{
|
||||||
|
if (drw)
|
||||||
|
drw->scheme = scm;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert)
|
||||||
|
{
|
||||||
|
if (!drw || !drw->scheme)
|
||||||
|
return;
|
||||||
|
XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme[ColBg].pixel : drw->scheme[ColFg].pixel);
|
||||||
|
if (filled)
|
||||||
|
XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
|
||||||
|
else
|
||||||
|
XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w - 1, h - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert)
|
||||||
|
{
|
||||||
|
char buf[1024];
|
||||||
|
int ty;
|
||||||
|
unsigned int ew;
|
||||||
|
XftDraw *d = NULL;
|
||||||
|
Fnt *usedfont, *curfont, *nextfont;
|
||||||
|
size_t i, len;
|
||||||
|
int utf8strlen, utf8charlen, render = x || y || w || h;
|
||||||
|
long utf8codepoint = 0;
|
||||||
|
const char *utf8str;
|
||||||
|
FcCharSet *fccharset;
|
||||||
|
FcPattern *fcpattern;
|
||||||
|
FcPattern *match;
|
||||||
|
XftResult result;
|
||||||
|
int charexists = 0;
|
||||||
|
|
||||||
|
if (!drw || (render && !drw->scheme) || !text || !drw->fonts)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!render) {
|
||||||
|
w = ~w;
|
||||||
|
} else {
|
||||||
|
XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel);
|
||||||
|
XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
|
||||||
|
d = XftDrawCreate(drw->dpy, drw->drawable, drw->visual, drw->cmap);
|
||||||
|
x += lpad;
|
||||||
|
w -= lpad;
|
||||||
|
}
|
||||||
|
|
||||||
|
usedfont = drw->fonts;
|
||||||
|
while (1) {
|
||||||
|
utf8strlen = 0;
|
||||||
|
utf8str = text;
|
||||||
|
nextfont = NULL;
|
||||||
|
while (*text) {
|
||||||
|
utf8charlen = utf8decode(text, &utf8codepoint, UTF_SIZ);
|
||||||
|
for (curfont = drw->fonts; curfont; curfont = curfont->next) {
|
||||||
|
charexists = charexists || XftCharExists(drw->dpy, curfont->xfont, utf8codepoint);
|
||||||
|
if (charexists) {
|
||||||
|
if (curfont == usedfont) {
|
||||||
|
utf8strlen += utf8charlen;
|
||||||
|
text += utf8charlen;
|
||||||
|
} else {
|
||||||
|
nextfont = curfont;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!charexists || nextfont)
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
charexists = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (utf8strlen) {
|
||||||
|
drw_font_getexts(usedfont, utf8str, utf8strlen, &ew, NULL);
|
||||||
|
/* shorten text if necessary */
|
||||||
|
for (len = MIN(utf8strlen, sizeof(buf) - 1); len && ew > w; len--)
|
||||||
|
drw_font_getexts(usedfont, utf8str, len, &ew, NULL);
|
||||||
|
|
||||||
|
if (len) {
|
||||||
|
memcpy(buf, utf8str, len);
|
||||||
|
buf[len] = '\0';
|
||||||
|
if (len < utf8strlen)
|
||||||
|
for (i = len; i && i > len - 3; buf[--i] = '.')
|
||||||
|
; /* NOP */
|
||||||
|
|
||||||
|
if (render) {
|
||||||
|
ty = y + (h - usedfont->h) / 2 + usedfont->xfont->ascent;
|
||||||
|
XftDrawStringUtf8(d, &drw->scheme[invert ? ColBg : ColFg],
|
||||||
|
usedfont->xfont, x, ty, (XftChar8 *)buf, len);
|
||||||
|
}
|
||||||
|
x += ew;
|
||||||
|
w -= ew;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!*text) {
|
||||||
|
break;
|
||||||
|
} else if (nextfont) {
|
||||||
|
charexists = 0;
|
||||||
|
usedfont = nextfont;
|
||||||
|
} else {
|
||||||
|
/* Regardless of whether or not a fallback font is found, the
|
||||||
|
* character must be drawn. */
|
||||||
|
charexists = 1;
|
||||||
|
|
||||||
|
fccharset = FcCharSetCreate();
|
||||||
|
FcCharSetAddChar(fccharset, utf8codepoint);
|
||||||
|
|
||||||
|
if (!drw->fonts->pattern) {
|
||||||
|
/* Refer to the comment in xfont_create for more information. */
|
||||||
|
die("the first font in the cache must be loaded from a font string.");
|
||||||
|
}
|
||||||
|
|
||||||
|
fcpattern = FcPatternDuplicate(drw->fonts->pattern);
|
||||||
|
FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset);
|
||||||
|
FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue);
|
||||||
|
FcPatternAddBool(fcpattern, FC_COLOR, FcFalse);
|
||||||
|
|
||||||
|
FcConfigSubstitute(NULL, fcpattern, FcMatchPattern);
|
||||||
|
FcDefaultSubstitute(fcpattern);
|
||||||
|
match = XftFontMatch(drw->dpy, drw->screen, fcpattern, &result);
|
||||||
|
|
||||||
|
FcCharSetDestroy(fccharset);
|
||||||
|
FcPatternDestroy(fcpattern);
|
||||||
|
|
||||||
|
if (match) {
|
||||||
|
usedfont = xfont_create(drw, NULL, match);
|
||||||
|
if (usedfont && XftCharExists(drw->dpy, usedfont->xfont, utf8codepoint)) {
|
||||||
|
for (curfont = drw->fonts; curfont->next; curfont = curfont->next)
|
||||||
|
; /* NOP */
|
||||||
|
curfont->next = usedfont;
|
||||||
|
} else {
|
||||||
|
xfont_free(usedfont);
|
||||||
|
usedfont = drw->fonts;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (d)
|
||||||
|
XftDrawDestroy(d);
|
||||||
|
|
||||||
|
return x + (render ? w : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h)
|
||||||
|
{
|
||||||
|
if (!drw)
|
||||||
|
return;
|
||||||
|
|
||||||
|
XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, y);
|
||||||
|
XSync(drw->dpy, False);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int
|
||||||
|
drw_fontset_getwidth(Drw *drw, const char *text)
|
||||||
|
{
|
||||||
|
if (!drw || !drw->fonts || !text)
|
||||||
|
return 0;
|
||||||
|
return drw_text(drw, 0, 0, 0, 0, 0, text, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h)
|
||||||
|
{
|
||||||
|
XGlyphInfo ext;
|
||||||
|
|
||||||
|
if (!font || !text)
|
||||||
|
return;
|
||||||
|
|
||||||
|
XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *)text, len, &ext);
|
||||||
|
if (w)
|
||||||
|
*w = ext.xOff;
|
||||||
|
if (h)
|
||||||
|
*h = font->h;
|
||||||
|
}
|
||||||
|
|
||||||
|
Cur *
|
||||||
|
drw_cur_create(Drw *drw, int shape)
|
||||||
|
{
|
||||||
|
Cur *cur;
|
||||||
|
|
||||||
|
if (!drw || !(cur = ecalloc(1, sizeof(Cur))))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
cur->cursor = XCreateFontCursor(drw->dpy, shape);
|
||||||
|
|
||||||
|
return cur;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
drw_cur_free(Drw *drw, Cur *cursor)
|
||||||
|
{
|
||||||
|
if (!cursor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
XFreeCursor(drw->dpy, cursor->cursor);
|
||||||
|
free(cursor);
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Cursor cursor;
|
||||||
|
} Cur;
|
||||||
|
|
||||||
|
typedef struct Fnt {
|
||||||
|
Display *dpy;
|
||||||
|
unsigned int h;
|
||||||
|
XftFont *xfont;
|
||||||
|
FcPattern *pattern;
|
||||||
|
struct Fnt *next;
|
||||||
|
} Fnt;
|
||||||
|
|
||||||
|
enum { ColFg, ColBg, ColBorder }; /* Clr scheme index */
|
||||||
|
typedef XftColor Clr;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned int w, h;
|
||||||
|
Display *dpy;
|
||||||
|
int screen;
|
||||||
|
Window root;
|
||||||
|
Visual *visual;
|
||||||
|
unsigned int depth;
|
||||||
|
Colormap cmap;
|
||||||
|
Drawable drawable;
|
||||||
|
GC gc;
|
||||||
|
Clr *scheme;
|
||||||
|
Fnt *fonts;
|
||||||
|
} Drw;
|
||||||
|
|
||||||
|
/* Drawable abstraction */
|
||||||
|
Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h, Visual *visual, unsigned int depth, Colormap cmap);
|
||||||
|
void drw_resize(Drw *drw, unsigned int w, unsigned int h);
|
||||||
|
void drw_free(Drw *drw);
|
||||||
|
|
||||||
|
/* Fnt abstraction */
|
||||||
|
Fnt *drw_fontset_create(Drw* drw, const char *fonts[], size_t fontcount);
|
||||||
|
void drw_fontset_free(Fnt* set);
|
||||||
|
unsigned int drw_fontset_getwidth(Drw *drw, const char *text);
|
||||||
|
void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h);
|
||||||
|
|
||||||
|
/* Colorscheme abstraction */
|
||||||
|
void drw_clr_create(Drw *drw, Clr *dest, const char *clrname, unsigned int alpha);
|
||||||
|
Clr *drw_scm_create(Drw *drw, const char *clrnames[], const unsigned int alphas[], size_t clrcount);
|
||||||
|
|
||||||
|
/* Cursor abstraction */
|
||||||
|
Cur *drw_cur_create(Drw *drw, int shape);
|
||||||
|
void drw_cur_free(Drw *drw, Cur *cursor);
|
||||||
|
|
||||||
|
/* Drawing context manipulation */
|
||||||
|
void drw_setfontset(Drw *drw, Fnt *set);
|
||||||
|
void drw_setscheme(Drw *drw, Clr *scm);
|
||||||
|
|
||||||
|
/* Drawing functions */
|
||||||
|
void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert);
|
||||||
|
int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert);
|
||||||
|
|
||||||
|
/* Map functions */
|
||||||
|
void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h);
|
||||||
@@ -0,0 +1,176 @@
|
|||||||
|
.TH DWM 1 dwm\-VERSION
|
||||||
|
.SH NAME
|
||||||
|
dwm \- dynamic window manager
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B dwm
|
||||||
|
.RB [ \-v ]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
dwm is a dynamic window manager for X. It manages windows in tiled, monocle
|
||||||
|
and floating layouts. Either layout can be applied dynamically, optimising the
|
||||||
|
environment for the application in use and the task performed.
|
||||||
|
.P
|
||||||
|
In tiled layouts windows are managed in a master and stacking area. The master
|
||||||
|
area on the left contains one window by default, and the stacking area on the
|
||||||
|
right contains all other windows. The number of master area windows can be
|
||||||
|
adjusted from zero to an arbitrary number. In monocle layout all windows are
|
||||||
|
maximised to the screen size. In floating layout windows can be resized and
|
||||||
|
moved freely. Dialog windows are always managed floating, regardless of the
|
||||||
|
layout applied.
|
||||||
|
.P
|
||||||
|
Windows are grouped by tags. Each window can be tagged with one or multiple
|
||||||
|
tags. Selecting certain tags displays all windows with these tags.
|
||||||
|
.P
|
||||||
|
Each screen contains a small status bar which displays all available tags, the
|
||||||
|
layout, the title of the focused window, and the text read from the root window
|
||||||
|
name property, if the screen is focused. A floating window is indicated with an
|
||||||
|
empty square and a maximised floating window is indicated with a filled square
|
||||||
|
before the windows title. The selected tags are indicated with a different
|
||||||
|
color. The tags of the focused window are indicated with a filled square in the
|
||||||
|
top left corner. The tags which are applied to one or more windows are
|
||||||
|
indicated with an empty square in the top left corner.
|
||||||
|
.P
|
||||||
|
dwm draws a small border around windows to indicate the focus state.
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
.B \-v
|
||||||
|
prints version information to stderr, then exits.
|
||||||
|
.SH USAGE
|
||||||
|
.SS Status bar
|
||||||
|
.TP
|
||||||
|
.B X root window name
|
||||||
|
is read and displayed in the status text area. It can be set with the
|
||||||
|
.BR xsetroot (1)
|
||||||
|
command.
|
||||||
|
.TP
|
||||||
|
.B Button1
|
||||||
|
click on a tag label to display all windows with that tag, click on the layout
|
||||||
|
label toggles between tiled and floating layout.
|
||||||
|
.TP
|
||||||
|
.B Button3
|
||||||
|
click on a tag label adds/removes all windows with that tag to/from the view.
|
||||||
|
.TP
|
||||||
|
.B Mod1\-Button1
|
||||||
|
click on a tag label applies that tag to the focused window.
|
||||||
|
.TP
|
||||||
|
.B Mod1\-Button3
|
||||||
|
click on a tag label adds/removes that tag to/from the focused window.
|
||||||
|
.SS Keyboard commands
|
||||||
|
.TP
|
||||||
|
.B Mod1\-Shift\-Return
|
||||||
|
Start
|
||||||
|
.BR st(1).
|
||||||
|
.TP
|
||||||
|
.B Mod1\-p
|
||||||
|
Spawn
|
||||||
|
.BR dmenu(1)
|
||||||
|
for launching other programs.
|
||||||
|
.TP
|
||||||
|
.B Mod1\-,
|
||||||
|
Focus previous screen, if any.
|
||||||
|
.TP
|
||||||
|
.B Mod1\-.
|
||||||
|
Focus next screen, if any.
|
||||||
|
.TP
|
||||||
|
.B Mod1\-Shift\-,
|
||||||
|
Send focused window to previous screen, if any.
|
||||||
|
.TP
|
||||||
|
.B Mod1\-Shift\-.
|
||||||
|
Send focused window to next screen, if any.
|
||||||
|
.TP
|
||||||
|
.B Mod1\-b
|
||||||
|
Toggles bar on and off.
|
||||||
|
.TP
|
||||||
|
.B Mod1\-t
|
||||||
|
Sets tiled layout.
|
||||||
|
.TP
|
||||||
|
.B Mod1\-f
|
||||||
|
Sets floating layout.
|
||||||
|
.TP
|
||||||
|
.B Mod1\-m
|
||||||
|
Sets monocle layout.
|
||||||
|
.TP
|
||||||
|
.B Mod1\-space
|
||||||
|
Toggles between current and previous layout.
|
||||||
|
.TP
|
||||||
|
.B Mod1\-j
|
||||||
|
Focus next window.
|
||||||
|
.TP
|
||||||
|
.B Mod1\-k
|
||||||
|
Focus previous window.
|
||||||
|
.TP
|
||||||
|
.B Mod1\-i
|
||||||
|
Increase number of windows in master area.
|
||||||
|
.TP
|
||||||
|
.B Mod1\-d
|
||||||
|
Decrease number of windows in master area.
|
||||||
|
.TP
|
||||||
|
.B Mod1\-l
|
||||||
|
Increase master area size.
|
||||||
|
.TP
|
||||||
|
.B Mod1\-h
|
||||||
|
Decrease master area size.
|
||||||
|
.TP
|
||||||
|
.B Mod1\-Return
|
||||||
|
Zooms/cycles focused window to/from master area (tiled layouts only).
|
||||||
|
.TP
|
||||||
|
.B Mod1\-Shift\-c
|
||||||
|
Close focused window.
|
||||||
|
.TP
|
||||||
|
.B Mod1\-Shift\-space
|
||||||
|
Toggle focused window between tiled and floating state.
|
||||||
|
.TP
|
||||||
|
.B Mod1\-Tab
|
||||||
|
Toggles to the previously selected tags.
|
||||||
|
.TP
|
||||||
|
.B Mod1\-Shift\-[1..n]
|
||||||
|
Apply nth tag to focused window.
|
||||||
|
.TP
|
||||||
|
.B Mod1\-Shift\-0
|
||||||
|
Apply all tags to focused window.
|
||||||
|
.TP
|
||||||
|
.B Mod1\-Control\-Shift\-[1..n]
|
||||||
|
Add/remove nth tag to/from focused window.
|
||||||
|
.TP
|
||||||
|
.B Mod1\-[1..n]
|
||||||
|
View all windows with nth tag.
|
||||||
|
.TP
|
||||||
|
.B Mod1\-0
|
||||||
|
View all windows with any tag.
|
||||||
|
.TP
|
||||||
|
.B Mod1\-Control\-[1..n]
|
||||||
|
Add/remove all windows with nth tag to/from the view.
|
||||||
|
.TP
|
||||||
|
.B Mod1\-Shift\-q
|
||||||
|
Quit dwm.
|
||||||
|
.SS Mouse commands
|
||||||
|
.TP
|
||||||
|
.B Mod1\-Button1
|
||||||
|
Move focused window while dragging. Tiled windows will be toggled to the floating state.
|
||||||
|
.TP
|
||||||
|
.B Mod1\-Button2
|
||||||
|
Toggles focused window between floating and tiled state.
|
||||||
|
.TP
|
||||||
|
.B Mod1\-Button3
|
||||||
|
Resize focused window while dragging. Tiled windows will be toggled to the floating state.
|
||||||
|
.SH CUSTOMIZATION
|
||||||
|
dwm is customized by creating a custom config.h and (re)compiling the source
|
||||||
|
code. This keeps it fast, secure and simple.
|
||||||
|
.SH SEE ALSO
|
||||||
|
.BR dmenu (1),
|
||||||
|
.BR st (1)
|
||||||
|
.SH ISSUES
|
||||||
|
Java applications which use the XToolkit/XAWT backend may draw grey windows
|
||||||
|
only. The XToolkit/XAWT backend breaks ICCCM-compliance in recent JDK 1.5 and early
|
||||||
|
JDK 1.6 versions, because it assumes a reparenting window manager. Possible workarounds
|
||||||
|
are using JDK 1.4 (which doesn't contain the XToolkit/XAWT backend) or setting the
|
||||||
|
environment variable
|
||||||
|
.BR AWT_TOOLKIT=MToolkit
|
||||||
|
(to use the older Motif backend instead) or running
|
||||||
|
.B xprop -root -f _NET_WM_NAME 32a -set _NET_WM_NAME LG3D
|
||||||
|
or
|
||||||
|
.B wmname LG3D
|
||||||
|
(to pretend that a non-reparenting window manager is running that the
|
||||||
|
XToolkit/XAWT backend can recognize) or when using OpenJDK setting the environment variable
|
||||||
|
.BR _JAVA_AWT_WM_NONREPARENTING=1 .
|
||||||
|
.SH BUGS
|
||||||
|
Send all bug reports with a patch to hackers@suckless.org.
|
||||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 373 B |
@@ -0,0 +1,2 @@
|
|||||||
|
# Caleb's pathes for dwm
|
||||||
|
I manully add patches, files in the dir only exist to keep track of which patches I added
|
||||||
@@ -0,0 +1,288 @@
|
|||||||
|
From ad5887df95fda706291c81ee143d0786a1717b12 Mon Sep 17 00:00:00 2001
|
||||||
|
From: getimiskon <getimiskon@disroot.org>
|
||||||
|
Date: Sat, 1 Apr 2023 16:22:01 +0300
|
||||||
|
Subject: [PATCH] Allow dwm to have translucent bars, while keeping all the
|
||||||
|
text on it opaque, just like the alpha-patch for st. Updated for 348f655.
|
||||||
|
|
||||||
|
---
|
||||||
|
config.def.h | 7 +++++++
|
||||||
|
config.mk | 2 +-
|
||||||
|
drw.c | 26 ++++++++++++-----------
|
||||||
|
drw.h | 9 +++++---
|
||||||
|
dwm.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++------
|
||||||
|
5 files changed, 81 insertions(+), 22 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/config.def.h b/config.def.h
|
||||||
|
index 9efa774..8b3789a 100644
|
||||||
|
--- a/config.def.h
|
||||||
|
+++ b/config.def.h
|
||||||
|
@@ -12,11 +12,18 @@ static const char col_gray2[] = "#444444";
|
||||||
|
static const char col_gray3[] = "#bbbbbb";
|
||||||
|
static const char col_gray4[] = "#eeeeee";
|
||||||
|
static const char col_cyan[] = "#005577";
|
||||||
|
+static const unsigned int baralpha = 0xd0;
|
||||||
|
+static const unsigned int borderalpha = OPAQUE;
|
||||||
|
static const char *colors[][3] = {
|
||||||
|
/* fg bg border */
|
||||||
|
[SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
|
||||||
|
[SchemeSel] = { col_gray4, col_cyan, col_cyan },
|
||||||
|
};
|
||||||
|
+static const unsigned int alphas[][3] = {
|
||||||
|
+ /* fg bg border*/
|
||||||
|
+ [SchemeNorm] = { OPAQUE, baralpha, borderalpha },
|
||||||
|
+ [SchemeSel] = { OPAQUE, baralpha, borderalpha },
|
||||||
|
+};
|
||||||
|
|
||||||
|
/* tagging */
|
||||||
|
static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
|
||||||
|
diff --git a/config.mk b/config.mk
|
||||||
|
index ba64d3d..d609c42 100644
|
||||||
|
--- a/config.mk
|
||||||
|
+++ b/config.mk
|
||||||
|
@@ -23,7 +23,7 @@ FREETYPEINC = /usr/include/freetype2
|
||||||
|
|
||||||
|
# includes and libs
|
||||||
|
INCS = -I${X11INC} -I${FREETYPEINC}
|
||||||
|
-LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS}
|
||||||
|
+LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -lXrender
|
||||||
|
|
||||||
|
# flags
|
||||||
|
CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
|
||||||
|
diff --git a/drw.c b/drw.c
|
||||||
|
index a58a2b4..d18e8d8 100644
|
||||||
|
--- a/drw.c
|
||||||
|
+++ b/drw.c
|
||||||
|
@@ -61,7 +61,7 @@ utf8decode(const char *c, long *u, size_t clen)
|
||||||
|
}
|
||||||
|
|
||||||
|
Drw *
|
||||||
|
-drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h)
|
||||||
|
+drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h, Visual *visual, unsigned int depth, Colormap cmap)
|
||||||
|
{
|
||||||
|
Drw *drw = ecalloc(1, sizeof(Drw));
|
||||||
|
|
||||||
|
@@ -70,8 +70,11 @@ drw_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h
|
||||||
|
drw->root = root;
|
||||||
|
drw->w = w;
|
||||||
|
drw->h = h;
|
||||||
|
- drw->drawable = XCreatePixmap(dpy, root, w, h, DefaultDepth(dpy, screen));
|
||||||
|
- drw->gc = XCreateGC(dpy, root, 0, NULL);
|
||||||
|
+ drw->visual = visual;
|
||||||
|
+ drw->depth = depth;
|
||||||
|
+ drw->cmap = cmap;
|
||||||
|
+ drw->drawable = XCreatePixmap(dpy, root, w, h, depth);
|
||||||
|
+ drw->gc = XCreateGC(dpy, drw->drawable, 0, NULL);
|
||||||
|
XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter);
|
||||||
|
|
||||||
|
return drw;
|
||||||
|
@@ -87,7 +90,7 @@ drw_resize(Drw *drw, unsigned int w, unsigned int h)
|
||||||
|
drw->h = h;
|
||||||
|
if (drw->drawable)
|
||||||
|
XFreePixmap(drw->dpy, drw->drawable);
|
||||||
|
- drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, DefaultDepth(drw->dpy, drw->screen));
|
||||||
|
+ drw->drawable = XCreatePixmap(drw->dpy, drw->root, w, h, drw->depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
@@ -181,21 +184,22 @@ drw_fontset_free(Fnt *font)
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
-drw_clr_create(Drw *drw, Clr *dest, const char *clrname)
|
||||||
|
+drw_clr_create(Drw *drw, Clr *dest, const char *clrname, unsigned int alpha)
|
||||||
|
{
|
||||||
|
if (!drw || !dest || !clrname)
|
||||||
|
return;
|
||||||
|
|
||||||
|
- if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen),
|
||||||
|
- DefaultColormap(drw->dpy, drw->screen),
|
||||||
|
+ if (!XftColorAllocName(drw->dpy, drw->visual, drw->cmap,
|
||||||
|
clrname, dest))
|
||||||
|
die("error, cannot allocate color '%s'", clrname);
|
||||||
|
+
|
||||||
|
+ dest->pixel = (dest->pixel & 0x00ffffffU) | (alpha << 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wrapper to create color schemes. The caller has to call free(3) on the
|
||||||
|
* returned color scheme when done using it. */
|
||||||
|
Clr *
|
||||||
|
-drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount)
|
||||||
|
+drw_scm_create(Drw *drw, const char *clrnames[], const unsigned int alphas[], size_t clrcount)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
Clr *ret;
|
||||||
|
@@ -205,7 +209,7 @@ drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for (i = 0; i < clrcount; i++)
|
||||||
|
- drw_clr_create(drw, &ret[i], clrnames[i]);
|
||||||
|
+ drw_clr_create(drw, &ret[i], clrnames[i], alphas[i]);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -263,9 +267,7 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
|
||||||
|
} else {
|
||||||
|
XSetForeground(drw->dpy, drw->gc, drw->scheme[invert ? ColFg : ColBg].pixel);
|
||||||
|
XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
|
||||||
|
- d = XftDrawCreate(drw->dpy, drw->drawable,
|
||||||
|
- DefaultVisual(drw->dpy, drw->screen),
|
||||||
|
- DefaultColormap(drw->dpy, drw->screen));
|
||||||
|
+ d = XftDrawCreate(drw->dpy, drw->drawable, drw->visual, drw->cmap);
|
||||||
|
x += lpad;
|
||||||
|
w -= lpad;
|
||||||
|
}
|
||||||
|
diff --git a/drw.h b/drw.h
|
||||||
|
index 6471431..2143533 100644
|
||||||
|
--- a/drw.h
|
||||||
|
+++ b/drw.h
|
||||||
|
@@ -20,6 +20,9 @@ typedef struct {
|
||||||
|
Display *dpy;
|
||||||
|
int screen;
|
||||||
|
Window root;
|
||||||
|
+ Visual *visual;
|
||||||
|
+ unsigned int depth;
|
||||||
|
+ Colormap cmap;
|
||||||
|
Drawable drawable;
|
||||||
|
GC gc;
|
||||||
|
Clr *scheme;
|
||||||
|
@@ -27,7 +30,7 @@ typedef struct {
|
||||||
|
} Drw;
|
||||||
|
|
||||||
|
/* Drawable abstraction */
|
||||||
|
-Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h);
|
||||||
|
+Drw *drw_create(Display *dpy, int screen, Window win, unsigned int w, unsigned int h, Visual *visual, unsigned int depth, Colormap cmap);
|
||||||
|
void drw_resize(Drw *drw, unsigned int w, unsigned int h);
|
||||||
|
void drw_free(Drw *drw);
|
||||||
|
|
||||||
|
@@ -39,8 +42,8 @@ unsigned int drw_fontset_getwidth_clamp(Drw *drw, const char *text, unsigned int
|
||||||
|
void drw_font_getexts(Fnt *font, const char *text, unsigned int len, unsigned int *w, unsigned int *h);
|
||||||
|
|
||||||
|
/* Colorscheme abstraction */
|
||||||
|
-void drw_clr_create(Drw *drw, Clr *dest, const char *clrname);
|
||||||
|
-Clr *drw_scm_create(Drw *drw, const char *clrnames[], size_t clrcount);
|
||||||
|
+void drw_clr_create(Drw *drw, Clr *dest, const char *clrname, unsigned int alpha);
|
||||||
|
+Clr *drw_scm_create(Drw *drw, const char *clrnames[], const unsigned int alphas[], size_t clrcount);
|
||||||
|
|
||||||
|
/* Cursor abstraction */
|
||||||
|
Cur *drw_cur_create(Drw *drw, int shape);
|
||||||
|
diff --git a/dwm.c b/dwm.c
|
||||||
|
index c2bd871..3b34de8 100644
|
||||||
|
--- a/dwm.c
|
||||||
|
+++ b/dwm.c
|
||||||
|
@@ -56,6 +56,7 @@
|
||||||
|
#define HEIGHT(X) ((X)->h + 2 * (X)->bw)
|
||||||
|
#define TAGMASK ((1 << LENGTH(tags)) - 1)
|
||||||
|
#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
|
||||||
|
+#define OPAQUE 0xffU
|
||||||
|
|
||||||
|
/* enums */
|
||||||
|
enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
|
||||||
|
@@ -232,6 +233,7 @@ static Monitor *wintomon(Window w);
|
||||||
|
static int xerror(Display *dpy, XErrorEvent *ee);
|
||||||
|
static int xerrordummy(Display *dpy, XErrorEvent *ee);
|
||||||
|
static int xerrorstart(Display *dpy, XErrorEvent *ee);
|
||||||
|
+static void xinitvisual();
|
||||||
|
static void zoom(const Arg *arg);
|
||||||
|
|
||||||
|
/* variables */
|
||||||
|
@@ -268,6 +270,11 @@ static Drw *drw;
|
||||||
|
static Monitor *mons, *selmon;
|
||||||
|
static Window root, wmcheckwin;
|
||||||
|
|
||||||
|
+static int useargb = 0;
|
||||||
|
+static Visual *visual;
|
||||||
|
+static int depth;
|
||||||
|
+static Colormap cmap;
|
||||||
|
+
|
||||||
|
/* configuration, allows nested code to access above variables */
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
@@ -1558,7 +1565,8 @@ setup(void)
|
||||||
|
sw = DisplayWidth(dpy, screen);
|
||||||
|
sh = DisplayHeight(dpy, screen);
|
||||||
|
root = RootWindow(dpy, screen);
|
||||||
|
- drw = drw_create(dpy, screen, root, sw, sh);
|
||||||
|
+ xinitvisual();
|
||||||
|
+ drw = drw_create(dpy, screen, root, sw, sh, visual, depth, cmap);
|
||||||
|
if (!drw_fontset_create(drw, fonts, LENGTH(fonts)))
|
||||||
|
die("no fonts could be loaded.");
|
||||||
|
lrpad = drw->fonts->h;
|
||||||
|
@@ -1586,7 +1594,7 @@ setup(void)
|
||||||
|
/* init appearance */
|
||||||
|
scheme = ecalloc(LENGTH(colors), sizeof(Clr *));
|
||||||
|
for (i = 0; i < LENGTH(colors); i++)
|
||||||
|
- scheme[i] = drw_scm_create(drw, colors[i], 3);
|
||||||
|
+ scheme[i] = drw_scm_create(drw, colors[i], alphas[i], 3);
|
||||||
|
/* init bars */
|
||||||
|
updatebars();
|
||||||
|
updatestatus();
|
||||||
|
@@ -1813,16 +1821,18 @@ updatebars(void)
|
||||||
|
Monitor *m;
|
||||||
|
XSetWindowAttributes wa = {
|
||||||
|
.override_redirect = True,
|
||||||
|
- .background_pixmap = ParentRelative,
|
||||||
|
+ .background_pixel = 0,
|
||||||
|
+ .border_pixel = 0,
|
||||||
|
+ .colormap = cmap,
|
||||||
|
.event_mask = ButtonPressMask|ExposureMask
|
||||||
|
};
|
||||||
|
XClassHint ch = {"dwm", "dwm"};
|
||||||
|
for (m = mons; m; m = m->next) {
|
||||||
|
if (m->barwin)
|
||||||
|
continue;
|
||||||
|
- m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, DefaultDepth(dpy, screen),
|
||||||
|
- CopyFromParent, DefaultVisual(dpy, screen),
|
||||||
|
- CWOverrideRedirect|CWBackPixmap|CWEventMask, &wa);
|
||||||
|
+ m->barwin = XCreateWindow(dpy, root, m->wx, m->by, m->ww, bh, 0, depth,
|
||||||
|
+ InputOutput, visual,
|
||||||
|
+ CWOverrideRedirect|CWBackPixel|CWBorderPixel|CWColormap|CWEventMask, &wa);
|
||||||
|
XDefineCursor(dpy, m->barwin, cursor[CurNormal]->cursor);
|
||||||
|
XMapRaised(dpy, m->barwin);
|
||||||
|
XSetClassHint(dpy, m->barwin, &ch);
|
||||||
|
@@ -2120,6 +2130,43 @@ xerrorstart(Display *dpy, XErrorEvent *ee)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
+void
|
||||||
|
+xinitvisual()
|
||||||
|
+{
|
||||||
|
+ XVisualInfo *infos;
|
||||||
|
+ XRenderPictFormat *fmt;
|
||||||
|
+ int nitems;
|
||||||
|
+ int i;
|
||||||
|
+
|
||||||
|
+ XVisualInfo tpl = {
|
||||||
|
+ .screen = screen,
|
||||||
|
+ .depth = 32,
|
||||||
|
+ .class = TrueColor
|
||||||
|
+ };
|
||||||
|
+ long masks = VisualScreenMask | VisualDepthMask | VisualClassMask;
|
||||||
|
+
|
||||||
|
+ infos = XGetVisualInfo(dpy, masks, &tpl, &nitems);
|
||||||
|
+ visual = NULL;
|
||||||
|
+ for(i = 0; i < nitems; i ++) {
|
||||||
|
+ fmt = XRenderFindVisualFormat(dpy, infos[i].visual);
|
||||||
|
+ if (fmt->type == PictTypeDirect && fmt->direct.alphaMask) {
|
||||||
|
+ visual = infos[i].visual;
|
||||||
|
+ depth = infos[i].depth;
|
||||||
|
+ cmap = XCreateColormap(dpy, root, visual, AllocNone);
|
||||||
|
+ useargb = 1;
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ XFree(infos);
|
||||||
|
+
|
||||||
|
+ if (! visual) {
|
||||||
|
+ visual = DefaultVisual(dpy, screen);
|
||||||
|
+ depth = DefaultDepth(dpy, screen);
|
||||||
|
+ cmap = DefaultColormap(dpy, screen);
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
void
|
||||||
|
zoom(const Arg *arg)
|
||||||
|
{
|
||||||
|
--
|
||||||
|
2.40.0
|
||||||
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
diff -up dwm/dwm.c dwmmod/dwm.c
|
||||||
|
--- dwm/dwm.c 2020-06-25 00:21:30.383692180 -0300
|
||||||
|
+++ dwmmod/dwm.c 2020-06-25 00:20:35.643692330 -0300
|
||||||
|
@@ -1057,6 +1057,8 @@ manage(Window w, XWindowAttributes *wa)
|
||||||
|
updatewindowtype(c);
|
||||||
|
updatesizehints(c);
|
||||||
|
updatewmhints(c);
|
||||||
|
+ c->x = c->mon->mx + (c->mon->mw - WIDTH(c)) / 2;
|
||||||
|
+ c->y = c->mon->my + (c->mon->mh - HEIGHT(c)) / 2;
|
||||||
|
XSelectInput(dpy, w, EnterWindowMask|FocusChangeMask|PropertyChangeMask|StructureNotifyMask);
|
||||||
|
grabbuttons(c, 0);
|
||||||
|
if (!c->isfloating)
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
diff --git a/dwm.c b/dwm.c
|
||||||
|
index 1d78655..a9e0ea4 100644
|
||||||
|
--- a/dwm.c
|
||||||
|
+++ b/dwm.c
|
||||||
|
@@ -160,6 +160,7 @@ static Bool applysizehints(Client *c, int *x, int *y, int *w, int *h, Bool inter
|
||||||
|
static void arrange(Monitor *m);
|
||||||
|
static void arrangemon(Monitor *m);
|
||||||
|
static void attach(Client *c);
|
||||||
|
+static void attachabove(Client *c);
|
||||||
|
static void attachstack(Client *c);
|
||||||
|
static void buttonpress(XEvent *e);
|
||||||
|
static void checkotherwm(void);
|
||||||
|
@@ -418,6 +419,19 @@ attach(Client *c) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
+attachabove(Client *c) {
|
||||||
|
+ if(c->mon->sel == NULL || c->mon->sel == c->mon->clients || c->mon->sel->isfloating) {
|
||||||
|
+ attach(c);
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ Client *at;
|
||||||
|
+ for(at = c->mon->clients; at->next != c->mon->sel; at = at->next);
|
||||||
|
+ c->next = at->next;
|
||||||
|
+ at->next = c;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void
|
||||||
|
attachstack(Client *c) {
|
||||||
|
c->snext = c->mon->stack;
|
||||||
|
c->mon->stack = c;
|
||||||
|
@@ -1155,7 +1169,7 @@ manage(Window w, XWindowAttributes *wa) {
|
||||||
|
c->isfloating = c->oldstate = trans != None || c->isfixed;
|
||||||
|
if(c->isfloating)
|
||||||
|
XRaiseWindow(dpy, c->win);
|
||||||
|
- attach(c);
|
||||||
|
+ attachabove(c);
|
||||||
|
attachstack(c);
|
||||||
|
XMoveResizeWindow(dpy, c->win, c->x + 2 * sw, c->y, c->w, c->h); /* some windows require this */
|
||||||
|
setclientstate(c, NormalState);
|
||||||
|
@@ -1480,7 +1494,7 @@ sendmon(Client *c, Monitor *m) {
|
||||||
|
detachstack(c);
|
||||||
|
c->mon = m;
|
||||||
|
c->tags = m->tagset[m->seltags]; /* assign tags of target monitor */
|
||||||
|
- attach(c);
|
||||||
|
+ attachabove(c);
|
||||||
|
attachstack(c);
|
||||||
|
focus(NULL);
|
||||||
|
arrange(NULL);
|
||||||
|
@@ -1900,7 +1914,7 @@ updategeom(void) {
|
||||||
|
m->clients = c->next;
|
||||||
|
detachstack(c);
|
||||||
|
c->mon = mons;
|
||||||
|
- attach(c);
|
||||||
|
+ attachabove(c);
|
||||||
|
attachstack(c);
|
||||||
|
}
|
||||||
|
if(m == selmon)
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
From 94362c75d92a77d11dfbfecce89394b2e0078cd0 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Finn Rayment <finn@rayment.fr>
|
||||||
|
Date: Sun, 21 Aug 2022 13:56:50 +1000
|
||||||
|
Subject: [PATCH] Added cursor warp for refocus and window spawn/death
|
||||||
|
|
||||||
|
---
|
||||||
|
dwm.c | 8 ++++++++
|
||||||
|
1 file changed, 8 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/dwm.c b/dwm.c
|
||||||
|
index a96f33c..f0e8a39 100644
|
||||||
|
--- a/dwm.c
|
||||||
|
+++ b/dwm.c
|
||||||
|
@@ -831,6 +831,8 @@ focusmon(const Arg *arg)
|
||||||
|
unfocus(selmon->sel, 0);
|
||||||
|
selmon = m;
|
||||||
|
focus(NULL);
|
||||||
|
+ if (selmon->sel)
|
||||||
|
+ XWarpPointer(dpy, None, selmon->sel->win, 0, 0, 0, 0, selmon->sel->w/2, selmon->sel->h/2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
@@ -856,6 +858,7 @@ focusstack(const Arg *arg)
|
||||||
|
if (c) {
|
||||||
|
focus(c);
|
||||||
|
restack(selmon);
|
||||||
|
+ XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w/2, c->h/2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -1077,6 +1080,8 @@ manage(Window w, XWindowAttributes *wa)
|
||||||
|
c->mon->sel = c;
|
||||||
|
arrange(c->mon);
|
||||||
|
XMapWindow(dpy, c->win);
|
||||||
|
+ if (c && c->mon == selmon)
|
||||||
|
+ XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, c->w/2, c->h/2);
|
||||||
|
focus(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -1788,6 +1793,9 @@ unmanage(Client *c, int destroyed)
|
||||||
|
focus(NULL);
|
||||||
|
updateclientlist();
|
||||||
|
arrange(m);
|
||||||
|
+ if (m == selmon && m->sel)
|
||||||
|
+ XWarpPointer(dpy, None, m->sel->win, 0, 0, 0, 0,
|
||||||
|
+ m->sel->w/2, m->sel->h/2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
--
|
||||||
|
2.35.1
|
||||||
|
|
||||||
@@ -0,0 +1,177 @@
|
|||||||
|
diff --git a/dwm.c b/dwm.c
|
||||||
|
index 664c527..ac8e4ec 100644
|
||||||
|
--- a/dwm.c
|
||||||
|
+++ b/dwm.c
|
||||||
|
@@ -111,6 +111,7 @@ typedef struct {
|
||||||
|
void (*arrange)(Monitor *);
|
||||||
|
} Layout;
|
||||||
|
|
||||||
|
+typedef struct Pertag Pertag;
|
||||||
|
struct Monitor {
|
||||||
|
char ltsymbol[16];
|
||||||
|
float mfact;
|
||||||
|
@@ -130,6 +131,7 @@ struct Monitor {
|
||||||
|
Monitor *next;
|
||||||
|
Window barwin;
|
||||||
|
const Layout *lt[2];
|
||||||
|
+ Pertag *pertag;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
@@ -272,6 +274,15 @@ static Window root, wmcheckwin;
|
||||||
|
/* configuration, allows nested code to access above variables */
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
+struct Pertag {
|
||||||
|
+ unsigned int curtag, prevtag; /* current and previous tag */
|
||||||
|
+ int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */
|
||||||
|
+ float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */
|
||||||
|
+ unsigned int sellts[LENGTH(tags) + 1]; /* selected layouts */
|
||||||
|
+ const Layout *ltidxs[LENGTH(tags) + 1][2]; /* matrix of tags and layouts indexes */
|
||||||
|
+ int showbars[LENGTH(tags) + 1]; /* display bar for the current tag */
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
/* compile-time check if all tags fit into an unsigned int bit array. */
|
||||||
|
struct NumTags { char limitexceeded[LENGTH(tags) > 31 ? -1 : 1]; };
|
||||||
|
|
||||||
|
@@ -632,6 +643,7 @@ Monitor *
|
||||||
|
createmon(void)
|
||||||
|
{
|
||||||
|
Monitor *m;
|
||||||
|
+ unsigned int i;
|
||||||
|
|
||||||
|
m = ecalloc(1, sizeof(Monitor));
|
||||||
|
m->tagset[0] = m->tagset[1] = 1;
|
||||||
|
@@ -642,6 +654,20 @@ createmon(void)
|
||||||
|
m->lt[0] = &layouts[0];
|
||||||
|
m->lt[1] = &layouts[1 % LENGTH(layouts)];
|
||||||
|
strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
|
||||||
|
+ m->pertag = ecalloc(1, sizeof(Pertag));
|
||||||
|
+ m->pertag->curtag = m->pertag->prevtag = 1;
|
||||||
|
+
|
||||||
|
+ for (i = 0; i <= LENGTH(tags); i++) {
|
||||||
|
+ m->pertag->nmasters[i] = m->nmaster;
|
||||||
|
+ m->pertag->mfacts[i] = m->mfact;
|
||||||
|
+
|
||||||
|
+ m->pertag->ltidxs[i][0] = m->lt[0];
|
||||||
|
+ m->pertag->ltidxs[i][1] = m->lt[1];
|
||||||
|
+ m->pertag->sellts[i] = m->sellt;
|
||||||
|
+
|
||||||
|
+ m->pertag->showbars[i] = m->showbar;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -967,7 +993,7 @@ grabkeys(void)
|
||||||
|
void
|
||||||
|
incnmaster(const Arg *arg)
|
||||||
|
{
|
||||||
|
- selmon->nmaster = MAX(selmon->nmaster + arg->i, 0);
|
||||||
|
+ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->nmaster + arg->i, 0);
|
||||||
|
arrange(selmon);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -1502,9 +1528,9 @@ void
|
||||||
|
setlayout(const Arg *arg)
|
||||||
|
{
|
||||||
|
if (!arg || !arg->v || arg->v != selmon->lt[selmon->sellt])
|
||||||
|
- selmon->sellt ^= 1;
|
||||||
|
+ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag] ^= 1;
|
||||||
|
if (arg && arg->v)
|
||||||
|
- selmon->lt[selmon->sellt] = (Layout *)arg->v;
|
||||||
|
+ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt] = (Layout *)arg->v;
|
||||||
|
strncpy(selmon->ltsymbol, selmon->lt[selmon->sellt]->symbol, sizeof selmon->ltsymbol);
|
||||||
|
if (selmon->sel)
|
||||||
|
arrange(selmon);
|
||||||
|
@@ -1523,7 +1549,7 @@ setmfact(const Arg *arg)
|
||||||
|
f = arg->f < 1.0 ? arg->f + selmon->mfact : arg->f - 1.0;
|
||||||
|
if (f < 0.05 || f > 0.95)
|
||||||
|
return;
|
||||||
|
- selmon->mfact = f;
|
||||||
|
+ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag] = f;
|
||||||
|
arrange(selmon);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -1702,7 +1728,7 @@ tile(Monitor *m)
|
||||||
|
void
|
||||||
|
togglebar(const Arg *arg)
|
||||||
|
{
|
||||||
|
- selmon->showbar = !selmon->showbar;
|
||||||
|
+ selmon->showbar = selmon->pertag->showbars[selmon->pertag->curtag] = !selmon->showbar;
|
||||||
|
updatebarpos(selmon);
|
||||||
|
XMoveResizeWindow(dpy, selmon->barwin, selmon->wx, selmon->by, selmon->ww, bh);
|
||||||
|
arrange(selmon);
|
||||||
|
@@ -1741,9 +1767,33 @@ void
|
||||||
|
toggleview(const Arg *arg)
|
||||||
|
{
|
||||||
|
unsigned int newtagset = selmon->tagset[selmon->seltags] ^ (arg->ui & TAGMASK);
|
||||||
|
+ int i;
|
||||||
|
|
||||||
|
if (newtagset) {
|
||||||
|
selmon->tagset[selmon->seltags] = newtagset;
|
||||||
|
+
|
||||||
|
+ if (newtagset == ~0) {
|
||||||
|
+ selmon->pertag->prevtag = selmon->pertag->curtag;
|
||||||
|
+ selmon->pertag->curtag = 0;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* test if the user did not select the same tag */
|
||||||
|
+ if (!(newtagset & 1 << (selmon->pertag->curtag - 1))) {
|
||||||
|
+ selmon->pertag->prevtag = selmon->pertag->curtag;
|
||||||
|
+ for (i = 0; !(newtagset & 1 << i); i++) ;
|
||||||
|
+ selmon->pertag->curtag = i + 1;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* apply settings for this view */
|
||||||
|
+ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag];
|
||||||
|
+ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag];
|
||||||
|
+ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
|
||||||
|
+ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
|
||||||
|
+ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1];
|
||||||
|
+
|
||||||
|
+ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag])
|
||||||
|
+ togglebar(NULL);
|
||||||
|
+
|
||||||
|
focus(NULL);
|
||||||
|
arrange(selmon);
|
||||||
|
}
|
||||||
|
@@ -2038,11 +2088,37 @@ updatewmhints(Client *c)
|
||||||
|
void
|
||||||
|
view(const Arg *arg)
|
||||||
|
{
|
||||||
|
+ int i;
|
||||||
|
+ unsigned int tmptag;
|
||||||
|
+
|
||||||
|
if ((arg->ui & TAGMASK) == selmon->tagset[selmon->seltags])
|
||||||
|
return;
|
||||||
|
selmon->seltags ^= 1; /* toggle sel tagset */
|
||||||
|
- if (arg->ui & TAGMASK)
|
||||||
|
+ if (arg->ui & TAGMASK) {
|
||||||
|
selmon->tagset[selmon->seltags] = arg->ui & TAGMASK;
|
||||||
|
+ selmon->pertag->prevtag = selmon->pertag->curtag;
|
||||||
|
+
|
||||||
|
+ if (arg->ui == ~0)
|
||||||
|
+ selmon->pertag->curtag = 0;
|
||||||
|
+ else {
|
||||||
|
+ for (i = 0; !(arg->ui & 1 << i); i++) ;
|
||||||
|
+ selmon->pertag->curtag = i + 1;
|
||||||
|
+ }
|
||||||
|
+ } else {
|
||||||
|
+ tmptag = selmon->pertag->prevtag;
|
||||||
|
+ selmon->pertag->prevtag = selmon->pertag->curtag;
|
||||||
|
+ selmon->pertag->curtag = tmptag;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ selmon->nmaster = selmon->pertag->nmasters[selmon->pertag->curtag];
|
||||||
|
+ selmon->mfact = selmon->pertag->mfacts[selmon->pertag->curtag];
|
||||||
|
+ selmon->sellt = selmon->pertag->sellts[selmon->pertag->curtag];
|
||||||
|
+ selmon->lt[selmon->sellt] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt];
|
||||||
|
+ selmon->lt[selmon->sellt^1] = selmon->pertag->ltidxs[selmon->pertag->curtag][selmon->sellt^1];
|
||||||
|
+
|
||||||
|
+ if (selmon->showbar != selmon->pertag->showbars[selmon->pertag->curtag])
|
||||||
|
+ togglebar(NULL);
|
||||||
|
+
|
||||||
|
focus(NULL);
|
||||||
|
arrange(selmon);
|
||||||
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
From 58414bee958f2e7ed91d6fe31f503ec4a406981b Mon Sep 17 00:00:00 2001
|
||||||
|
From: cirala <thim@cederlund.de>
|
||||||
|
Date: Fri, 19 Nov 2021 18:14:07 +0100
|
||||||
|
Subject: [PATCH] Fix for dwm-uselessgap
|
||||||
|
Previous versions of the patch doubles the
|
||||||
|
gap between the master and slave stacks.
|
||||||
|
|
||||||
|
---
|
||||||
|
config.def.h | 3 ++-
|
||||||
|
dwm.c | 38 +++++++++++++++++++++++++++++++-------
|
||||||
|
2 files changed, 33 insertions(+), 8 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/config.def.h b/config.def.h
|
||||||
|
index a2ac963..17a205f 100644
|
||||||
|
--- a/config.def.h
|
||||||
|
+++ b/config.def.h
|
||||||
|
@@ -2,6 +2,7 @@
|
||||||
|
|
||||||
|
/* appearance */
|
||||||
|
static const unsigned int borderpx = 1; /* border pixel of windows */
|
||||||
|
+static const unsigned int gappx = 6; /* gaps between windows */
|
||||||
|
static const unsigned int snap = 32; /* snap pixel */
|
||||||
|
static const int showbar = 1; /* 0 means no bar */
|
||||||
|
static const int topbar = 1; /* 0 means bottom bar */
|
||||||
|
@@ -34,7 +35,7 @@ static const Rule rules[] = {
|
||||||
|
/* layout(s) */
|
||||||
|
static const float mfact = 0.55; /* factor of master area size [0.05..0.95] */
|
||||||
|
static const int nmaster = 1; /* number of clients in master area */
|
||||||
|
-static const int resizehints = 1; /* 1 means respect size hints in tiled resizals */
|
||||||
|
+static const int resizehints = 0; /* 1 means respect size hints in tiled resizals */
|
||||||
|
static const int lockfullscreen = 1; /* 1 will force focus on the fullscreen window */
|
||||||
|
|
||||||
|
static const Layout layouts[] = {
|
||||||
|
diff --git a/dwm.c b/dwm.c
|
||||||
|
index 5e4d494..b626e89 100644
|
||||||
|
--- a/dwm.c
|
||||||
|
+++ b/dwm.c
|
||||||
|
@@ -52,8 +52,8 @@
|
||||||
|
#define ISVISIBLE(C) ((C->tags & C->mon->tagset[C->mon->seltags]))
|
||||||
|
#define LENGTH(X) (sizeof X / sizeof X[0])
|
||||||
|
#define MOUSEMASK (BUTTONMASK|PointerMotionMask)
|
||||||
|
-#define WIDTH(X) ((X)->w + 2 * (X)->bw)
|
||||||
|
-#define HEIGHT(X) ((X)->h + 2 * (X)->bw)
|
||||||
|
+#define WIDTH(X) ((X)->w + 2 * (X)->bw + gappx)
|
||||||
|
+#define HEIGHT(X) ((X)->h + 2 * (X)->bw + gappx)
|
||||||
|
#define TAGMASK ((1 << LENGTH(tags)) - 1)
|
||||||
|
#define TEXTW(X) (drw_fontset_getwidth(drw, (X)) + lrpad)
|
||||||
|
|
||||||
|
@@ -1277,12 +1277,36 @@ void
|
||||||
|
resizeclient(Client *c, int x, int y, int w, int h)
|
||||||
|
{
|
||||||
|
XWindowChanges wc;
|
||||||
|
+ unsigned int n;
|
||||||
|
+ unsigned int gapoffset;
|
||||||
|
+ unsigned int gapincr;
|
||||||
|
+ Client *nbc;
|
||||||
|
|
||||||
|
- c->oldx = c->x; c->x = wc.x = x;
|
||||||
|
- c->oldy = c->y; c->y = wc.y = y;
|
||||||
|
- c->oldw = c->w; c->w = wc.width = w;
|
||||||
|
- c->oldh = c->h; c->h = wc.height = h;
|
||||||
|
wc.border_width = c->bw;
|
||||||
|
+
|
||||||
|
+ /* Get number of clients for the client's monitor */
|
||||||
|
+ for (n = 0, nbc = nexttiled(c->mon->clients); nbc; nbc = nexttiled(nbc->next), n++);
|
||||||
|
+
|
||||||
|
+ /* Do nothing if layout is floating */
|
||||||
|
+ if (c->isfloating || c->mon->lt[c->mon->sellt]->arrange == NULL) {
|
||||||
|
+ gapincr = gapoffset = 0;
|
||||||
|
+ } else {
|
||||||
|
+ /* Remove border and gap if layout is monocle or only one client */
|
||||||
|
+ if (c->mon->lt[c->mon->sellt]->arrange == monocle || n == 1) {
|
||||||
|
+ gapoffset = 0;
|
||||||
|
+ gapincr = -2 * borderpx;
|
||||||
|
+ wc.border_width = 0;
|
||||||
|
+ } else {
|
||||||
|
+ gapoffset = gappx;
|
||||||
|
+ gapincr = 2 * gappx;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ c->oldx = c->x; c->x = wc.x = x + gapoffset;
|
||||||
|
+ c->oldy = c->y; c->y = wc.y = y + gapoffset;
|
||||||
|
+ c->oldw = c->w; c->w = wc.width = w - gapincr;
|
||||||
|
+ c->oldh = c->h; c->h = wc.height = h - gapincr;
|
||||||
|
+
|
||||||
|
XConfigureWindow(dpy, c->win, CWX|CWY|CWWidth|CWHeight|CWBorderWidth, &wc);
|
||||||
|
configure(c);
|
||||||
|
XSync(dpy, False);
|
||||||
|
@@ -1688,7 +1712,7 @@ tile(Monitor *m)
|
||||||
|
for (i = my = ty = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
|
||||||
|
if (i < m->nmaster) {
|
||||||
|
h = (m->wh - my) / (MIN(n, m->nmaster) - i);
|
||||||
|
- resize(c, m->wx, m->wy + my, mw - (2*c->bw), h - (2*c->bw), 0);
|
||||||
|
+ resize(c, m->wx, m->wy + my, mw - (2*c->bw) + (n > 1 ? gappx : 0), h - (2*c->bw), 0);
|
||||||
|
if (my + HEIGHT(c) < m->wh)
|
||||||
|
my += HEIGHT(c);
|
||||||
|
} else {
|
||||||
|
--
|
||||||
|
2.33.1
|
||||||
|
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
/** Function to shift the current view to the left/right
|
||||||
|
*
|
||||||
|
* @param: "arg->i" stores the number of tags to shift right (positive value)
|
||||||
|
* or left (negative value)
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
shiftview(const Arg *arg) {
|
||||||
|
Arg shifted;
|
||||||
|
|
||||||
|
if(arg->i > 0) // left circular shift
|
||||||
|
shifted.ui = (selmon->tagset[selmon->seltags] << arg->i)
|
||||||
|
| (selmon->tagset[selmon->seltags] >> (LENGTH(tags) - arg->i));
|
||||||
|
|
||||||
|
else // right circular shift
|
||||||
|
shifted.ui = selmon->tagset[selmon->seltags] >> (- arg->i)
|
||||||
|
| selmon->tagset[selmon->seltags] << (LENGTH(tags) + arg->i);
|
||||||
|
|
||||||
|
view(&shifted);
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
/* cc transient.c -o transient -lX11 */
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include <X11/Xutil.h>
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
Display *d;
|
||||||
|
Window r, f, t = None;
|
||||||
|
XSizeHints h;
|
||||||
|
XEvent e;
|
||||||
|
|
||||||
|
d = XOpenDisplay(NULL);
|
||||||
|
if (!d)
|
||||||
|
exit(1);
|
||||||
|
r = DefaultRootWindow(d);
|
||||||
|
|
||||||
|
f = XCreateSimpleWindow(d, r, 100, 100, 400, 400, 0, 0, 0);
|
||||||
|
h.min_width = h.max_width = h.min_height = h.max_height = 400;
|
||||||
|
h.flags = PMinSize | PMaxSize;
|
||||||
|
XSetWMNormalHints(d, f, &h);
|
||||||
|
XStoreName(d, f, "floating");
|
||||||
|
XMapWindow(d, f);
|
||||||
|
|
||||||
|
XSelectInput(d, f, ExposureMask);
|
||||||
|
while (1) {
|
||||||
|
XNextEvent(d, &e);
|
||||||
|
|
||||||
|
if (t == None) {
|
||||||
|
sleep(5);
|
||||||
|
t = XCreateSimpleWindow(d, r, 50, 50, 100, 100, 0, 0, 0);
|
||||||
|
XSetTransientForHint(d, t, f);
|
||||||
|
XStoreName(d, t, "transient");
|
||||||
|
XMapWindow(d, t);
|
||||||
|
XSelectInput(d, t, ExposureMask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
XCloseDisplay(d);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
+35
@@ -0,0 +1,35 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
void *
|
||||||
|
ecalloc(size_t nmemb, size_t size)
|
||||||
|
{
|
||||||
|
void *p;
|
||||||
|
|
||||||
|
if (!(p = calloc(nmemb, size)))
|
||||||
|
die("calloc:");
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
die(const char *fmt, ...) {
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vfprintf(stderr, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
if (fmt[0] && fmt[strlen(fmt)-1] == ':') {
|
||||||
|
fputc(' ', stderr);
|
||||||
|
perror(NULL);
|
||||||
|
} else {
|
||||||
|
fputc('\n', stderr);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
|
||||||
|
#define MAX(A, B) ((A) > (B) ? (A) : (B))
|
||||||
|
#define MIN(A, B) ((A) < (B) ? (A) : (B))
|
||||||
|
#define BETWEEN(X, A, B) ((A) <= (X) && (X) <= (B))
|
||||||
|
|
||||||
|
void die(const char *fmt, ...);
|
||||||
|
void *ecalloc(size_t nmemb, size_t size);
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
# path: /home/klassiker/.local/share/repos/st/.gitignore
|
||||||
|
# author: klassiker [mrdotx]
|
||||||
|
# github: https://github.com/mrdotx/st
|
||||||
|
# date: 2021-05-20T10:29:57+0200
|
||||||
|
|
||||||
|
/boxdraw.o
|
||||||
|
/config.h
|
||||||
|
/st
|
||||||
|
/st.o
|
||||||
|
/x.o
|
||||||
@@ -0,0 +1,252 @@
|
|||||||
|
## Why does st not handle utmp entries?
|
||||||
|
|
||||||
|
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!
|
||||||
|
|
||||||
|
It means that st doesn’t have any terminfo entry on your system. Chances are
|
||||||
|
you did not `make install`. If you just want to test it without installing it,
|
||||||
|
you can manually run `tic -sx st.info`.
|
||||||
|
|
||||||
|
|
||||||
|
## Nothing works, and nothing is said about an unknown terminal!
|
||||||
|
|
||||||
|
* Some programs just assume they’re running in xterm i.e. they don’t rely on
|
||||||
|
terminfo. What you see is the current state of the “xterm compliance”.
|
||||||
|
* Some programs don’t complain about the lacking st description and default to
|
||||||
|
another terminal. In that case see the question about terminfo.
|
||||||
|
|
||||||
|
|
||||||
|
## How do I scroll back up?
|
||||||
|
|
||||||
|
* Using a terminal multiplexer.
|
||||||
|
* `st -e tmux` using C-b [
|
||||||
|
* `st -e screen` using C-a ESC
|
||||||
|
* Using the excellent tool of [scroll](https://git.suckless.org/scroll/).
|
||||||
|
* Using the scrollback [patch](https://st.suckless.org/patches/scrollback/).
|
||||||
|
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
|
||||||
|
## Why doesn't the Del key work in some programs?
|
||||||
|
|
||||||
|
Taken from the terminfo manpage:
|
||||||
|
|
||||||
|
If the terminal has a keypad that transmits codes when the keys
|
||||||
|
are pressed, this information can be given. Note that it is not
|
||||||
|
possible to handle terminals where the keypad only works in
|
||||||
|
local (this applies, for example, to the unshifted HP 2621 keys).
|
||||||
|
If the keypad can be set to transmit or not transmit, give these
|
||||||
|
codes as smkx and rmkx. Otherwise the keypad is assumed to
|
||||||
|
always transmit.
|
||||||
|
|
||||||
|
In the st case smkx=E[?1hE= and rmkx=E[?1lE>, so it is mandatory that
|
||||||
|
applications which want to test against keypad keys send these
|
||||||
|
sequences.
|
||||||
|
|
||||||
|
But buggy applications (like bash and irssi, for example) don't do this. A fast
|
||||||
|
solution for them is to use the following command:
|
||||||
|
|
||||||
|
$ printf '\033[?1h\033=' >/dev/tty
|
||||||
|
|
||||||
|
or
|
||||||
|
$ tput smkx
|
||||||
|
|
||||||
|
In the case of bash, readline is used. Readline has a different note in its
|
||||||
|
manpage about this issue:
|
||||||
|
|
||||||
|
enable-keypad (Off)
|
||||||
|
When set to On, readline will try to enable the
|
||||||
|
application keypad when it is called. Some systems
|
||||||
|
need this to enable arrow keys.
|
||||||
|
|
||||||
|
Adding this option to your .inputrc will fix the keypad problem for all
|
||||||
|
applications using readline.
|
||||||
|
|
||||||
|
If you are using zsh, then read the zsh FAQ
|
||||||
|
<http://zsh.sourceforge.net/FAQ/zshfaq03.html#l25>:
|
||||||
|
|
||||||
|
It should be noted that the O / [ confusion can occur with other keys
|
||||||
|
such as Home and End. Some systems let you query the key sequences
|
||||||
|
sent by these keys from the system's terminal database, terminfo.
|
||||||
|
Unfortunately, the key sequences given there typically apply to the
|
||||||
|
mode that is not the one zsh uses by default (it's the "application"
|
||||||
|
mode rather than the "raw" mode). Explaining the use of terminfo is
|
||||||
|
outside of the scope of this FAQ, but if you wish to use the key
|
||||||
|
sequences given there you can tell the line editor to turn on
|
||||||
|
"application" mode when it starts and turn it off when it stops:
|
||||||
|
|
||||||
|
function zle-line-init () { echoti smkx }
|
||||||
|
function zle-line-finish () { echoti rmkx }
|
||||||
|
zle -N zle-line-init
|
||||||
|
zle -N zle-line-finish
|
||||||
|
|
||||||
|
Putting these lines into your .zshrc will fix the problems.
|
||||||
|
|
||||||
|
|
||||||
|
## How can I use meta in 8bit mode?
|
||||||
|
|
||||||
|
St supports meta in 8bit mode, but the default terminfo entry doesn't
|
||||||
|
use this capability. If you want it, you have to use the 'st-meta' value
|
||||||
|
in TERM.
|
||||||
|
|
||||||
|
|
||||||
|
## I cannot compile st in OpenBSD
|
||||||
|
|
||||||
|
OpenBSD lacks librt, despite it being mandatory in POSIX
|
||||||
|
<http://pubs.opengroup.org/onlinepubs/9699919799/utilities/c99.html#tag_20_11_13>.
|
||||||
|
If you want to compile st for OpenBSD you have to remove -lrt from config.mk, and
|
||||||
|
st will compile without any loss of functionality, because all the functions are
|
||||||
|
included in libc on this platform.
|
||||||
|
|
||||||
|
|
||||||
|
## The Backspace Case
|
||||||
|
|
||||||
|
St is emulating the Linux way of handling backspace being delete and delete being
|
||||||
|
backspace.
|
||||||
|
|
||||||
|
This is an issue that was discussed in suckless mailing list
|
||||||
|
<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:
|
||||||
|
|
||||||
|
Well, I am going to comment why I want to change the behaviour
|
||||||
|
of this key. When ASCII was defined in 1968, communication
|
||||||
|
with computers was done using punched cards, or hardcopy
|
||||||
|
terminals (basically a typewriter machine connected with the
|
||||||
|
computer using a serial port). ASCII defines DELETE as 7F,
|
||||||
|
because, in punched-card terms, it means all the holes of the
|
||||||
|
card punched; it is thus a kind of 'physical delete'. In the
|
||||||
|
same way, the BACKSPACE key was a non-destructive backspace,
|
||||||
|
as on a typewriter. So, if you wanted to delete a character,
|
||||||
|
you had to BACKSPACE and then DELETE. Another use of BACKSPACE
|
||||||
|
was to type accented characters, for example 'a BACKSPACE `'.
|
||||||
|
The VT100 had no BACKSPACE key; it was generated using the
|
||||||
|
CONTROL key as another control character (CONTROL key sets to
|
||||||
|
0 b7 b6 b5, so it converts H (code 0x48) into BACKSPACE (code
|
||||||
|
0x08)), but it had a DELETE key in a similar position where
|
||||||
|
the BACKSPACE key is located today on common PC keyboards.
|
||||||
|
All the terminal emulators emulated the difference between
|
||||||
|
these keys correctly: the backspace key generated a BACKSPACE
|
||||||
|
(^H) and delete key generated a DELETE (^?).
|
||||||
|
|
||||||
|
But a problem arose when Linus Torvalds wrote Linux. Unlike
|
||||||
|
earlier terminals, the Linux virtual terminal (the terminal
|
||||||
|
emulator integrated in the kernel) returned a DELETE when
|
||||||
|
backspace was pressed, due to the VT100 having a DELETE key in
|
||||||
|
the same position. This created a lot of problems (see [1]
|
||||||
|
and [2]). Since Linux has become the king, a lot of terminal
|
||||||
|
emulators today generate a DELETE when the backspace key is
|
||||||
|
pressed in order to avoid problems with Linux. The result is
|
||||||
|
that the only way of generating a BACKSPACE on these systems
|
||||||
|
is by using CONTROL + H. (I also think that emacs had an
|
||||||
|
important point here because the CONTROL + H prefix is used
|
||||||
|
in emacs in some commands (help commands).)
|
||||||
|
|
||||||
|
From point of view of the kernel, you can change the key
|
||||||
|
for deleting a previous character with stty erase. When you
|
||||||
|
connect a real terminal into a machine you describe the type
|
||||||
|
of terminal, so getty configures the correct value of stty
|
||||||
|
erase for this terminal. In the case of terminal emulators,
|
||||||
|
however, you don't have any getty that can set the correct
|
||||||
|
value of stty erase, so you always get the default value.
|
||||||
|
For this reason, it is necessary to add 'stty erase ^H' to your
|
||||||
|
profile if you have changed the value of the backspace key.
|
||||||
|
Of course, another solution is for st itself to modify the
|
||||||
|
value of stty erase. I usually have the inverse problem:
|
||||||
|
when I connect to non-Unix machines, I have to press CONTROL +
|
||||||
|
h to get a BACKSPACE. The inverse problem occurs when a user
|
||||||
|
connects to my Unix machines from a different system with a
|
||||||
|
correct backspace key.
|
||||||
|
|
||||||
|
[1] http://www.ibb.net/~anne/keyboard.html
|
||||||
|
[2] http://www.tldp.org/HOWTO/Keyboard-and-Console-HOWTO-5.html
|
||||||
|
|
||||||
|
|
||||||
|
## But I really want the old grumpy behaviour of my terminal
|
||||||
|
|
||||||
|
Apply [1].
|
||||||
|
|
||||||
|
[1] https://st.suckless.org/patches/delkey
|
||||||
|
|
||||||
|
|
||||||
|
## Why do images not work in st using the w3m image hack?
|
||||||
|
|
||||||
|
w3mimg uses a hack that draws an image on top of the terminal emulator Drawable
|
||||||
|
window. The hack relies on the terminal to use a single buffer to draw its
|
||||||
|
contents directly.
|
||||||
|
|
||||||
|
st uses double-buffered drawing so the image is quickly replaced and may show a
|
||||||
|
short flicker effect.
|
||||||
|
|
||||||
|
Below is a patch example to change st double-buffering to a single Drawable
|
||||||
|
buffer.
|
||||||
|
|
||||||
|
diff --git a/x.c b/x.c
|
||||||
|
--- a/x.c
|
||||||
|
+++ b/x.c
|
||||||
|
@@ -732,10 +732,6 @@ xresize(int col, int row)
|
||||||
|
win.tw = col * win.cw;
|
||||||
|
win.th = row * win.ch;
|
||||||
|
|
||||||
|
- XFreePixmap(xw.dpy, xw.buf);
|
||||||
|
- xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h,
|
||||||
|
- DefaultDepth(xw.dpy, xw.scr));
|
||||||
|
- XftDrawChange(xw.draw, xw.buf);
|
||||||
|
xclear(0, 0, win.w, win.h);
|
||||||
|
|
||||||
|
/* resize to new width */
|
||||||
|
@@ -1148,8 +1144,7 @@ xinit(int cols, int rows)
|
||||||
|
gcvalues.graphics_exposures = False;
|
||||||
|
dc.gc = XCreateGC(xw.dpy, parent, GCGraphicsExposures,
|
||||||
|
&gcvalues);
|
||||||
|
- xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h,
|
||||||
|
- DefaultDepth(xw.dpy, xw.scr));
|
||||||
|
+ xw.buf = xw.win;
|
||||||
|
XSetForeground(xw.dpy, dc.gc, dc.col[defaultbg].pixel);
|
||||||
|
XFillRectangle(xw.dpy, xw.buf, dc.gc, 0, 0, win.w, win.h);
|
||||||
|
|
||||||
|
@@ -1632,8 +1627,6 @@ xdrawline(Line line, int x1, int y1, int x2)
|
||||||
|
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);
|
||||||
|
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
|
||||||
|
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
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
A STATEMENT ON LEGACY SUPPORT
|
||||||
|
|
||||||
|
In the terminal world there is much cruft that comes from old and unsup‐
|
||||||
|
ported terminals that inherit incompatible modes and escape sequences
|
||||||
|
which noone is able to know, except when he/she comes from that time and
|
||||||
|
developed a graphical vt100 emulator at that time.
|
||||||
|
|
||||||
|
One goal of st is to only support what is really needed. When you en‐
|
||||||
|
counter a sequence which you really need, implement it. But while you
|
||||||
|
are at it, do not add the other cruft you might encounter while sneek‐
|
||||||
|
ing at other terminal emulators. History has bloated them and there is
|
||||||
|
no real evidence that most of the sequences are used today.
|
||||||
|
|
||||||
|
|
||||||
|
Christoph Lohmann <20h@r-36.net>
|
||||||
|
2012-09-13T07:00:36.081271045+02:00
|
||||||
|
|
||||||
+34
@@ -0,0 +1,34 @@
|
|||||||
|
MIT/X Consortium License
|
||||||
|
|
||||||
|
© 2014-2022 Hiltjo Posthuma <hiltjo at codemadness dot org>
|
||||||
|
© 2018 Devin J. Pohly <djpohly at gmail dot com>
|
||||||
|
© 2014-2017 Quentin Rameau <quinq at fifth dot space>
|
||||||
|
© 2009-2012 Aurélien APTEL <aurelien dot aptel at gmail dot com>
|
||||||
|
© 2008-2017 Anselm R Garbe <garbeam at gmail dot com>
|
||||||
|
© 2012-2017 Roberto E. Vargas Caballero <k0ga at shike2 dot com>
|
||||||
|
© 2012-2016 Christoph Lohmann <20h at r-36 dot net>
|
||||||
|
© 2013 Eon S. Jeon <esjeon at hyunmu dot am>
|
||||||
|
© 2013 Alexander Sedov <alex0player at gmail dot com>
|
||||||
|
© 2013 Mark Edgar <medgar123 at gmail dot com>
|
||||||
|
© 2013-2014 Eric Pruitt <eric.pruitt at gmail dot com>
|
||||||
|
© 2013 Michael Forney <mforney at mforney dot org>
|
||||||
|
© 2013-2014 Markus Teich <markus dot teich at stusta dot mhn dot de>
|
||||||
|
© 2014-2015 Laslo Hunhold <dev at frign dot de>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
copy of this software and associated documentation files (the "Software"),
|
||||||
|
to deal in the Software without restriction, including without limitation
|
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
||||||
+52
@@ -0,0 +1,52 @@
|
|||||||
|
# st - simple terminal
|
||||||
|
# See LICENSE file for copyright and license details.
|
||||||
|
.POSIX:
|
||||||
|
|
||||||
|
include config.mk
|
||||||
|
|
||||||
|
SRC = st.c x.c boxdraw.c
|
||||||
|
OBJ = $(SRC:.c=.o)
|
||||||
|
|
||||||
|
all: st
|
||||||
|
|
||||||
|
config.h:
|
||||||
|
cp config.def.h config.h
|
||||||
|
|
||||||
|
.c.o:
|
||||||
|
$(CC) $(STCFLAGS) -c $<
|
||||||
|
|
||||||
|
st.o: config.h st.h win.h
|
||||||
|
x.o: arg.h config.h st.h win.h
|
||||||
|
boxdraw.o: config.h st.h boxdraw_data.h
|
||||||
|
|
||||||
|
$(OBJ): config.h config.mk
|
||||||
|
|
||||||
|
st: $(OBJ)
|
||||||
|
$(CC) -o $@ $(OBJ) $(STLDFLAGS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f st $(OBJ) st-$(VERSION).tar.gz
|
||||||
|
|
||||||
|
dist: clean
|
||||||
|
mkdir -p st-$(VERSION)
|
||||||
|
cp -R FAQ LEGACY TODO LICENSE Makefile README config.mk\
|
||||||
|
config.def.h st.info st.1 arg.h st.h win.h $(SRC)\
|
||||||
|
st-$(VERSION)
|
||||||
|
tar -cf - st-$(VERSION) | gzip > st-$(VERSION).tar.gz
|
||||||
|
rm -rf st-$(VERSION)
|
||||||
|
|
||||||
|
install: st
|
||||||
|
mkdir -p $(DESTDIR)$(PREFIX)/bin
|
||||||
|
cp -f st $(DESTDIR)$(PREFIX)/bin
|
||||||
|
chmod 755 $(DESTDIR)$(PREFIX)/bin/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
|
||||||
|
@echo Please see the README file regarding the terminfo entry of st.
|
||||||
|
|
||||||
|
uninstall:
|
||||||
|
rm -f $(DESTDIR)$(PREFIX)/bin/st
|
||||||
|
rm -f $(DESTDIR)$(MANPREFIX)/man1/st.1
|
||||||
|
|
||||||
|
.PHONY: all clean dist install uninstall
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
st - simple terminal
|
||||||
|
--------------------
|
||||||
|
st is a simple terminal emulator for X which sucks less.
|
||||||
|
|
||||||
|
|
||||||
|
Requirements
|
||||||
|
------------
|
||||||
|
In order to build st you need the Xlib header files.
|
||||||
|
|
||||||
|
|
||||||
|
Installation
|
||||||
|
------------
|
||||||
|
Edit config.mk to match your local setup (st is installed into
|
||||||
|
the /usr/local namespace by default).
|
||||||
|
|
||||||
|
Afterwards enter the following command to build and install st (if
|
||||||
|
necessary as root):
|
||||||
|
|
||||||
|
make clean install
|
||||||
|
|
||||||
|
|
||||||
|
Running st
|
||||||
|
----------
|
||||||
|
If you did not install st with make clean install, you must compile
|
||||||
|
the st terminfo entry with the following command:
|
||||||
|
|
||||||
|
tic -sx st.info
|
||||||
|
|
||||||
|
See the man page for additional details.
|
||||||
|
|
||||||
|
Credits
|
||||||
|
-------
|
||||||
|
Based on Aurélien APTEL <aurelien dot aptel at gmail dot com> bt source code.
|
||||||
|
|
||||||
|
Version
|
||||||
|
-------
|
||||||
|
0.9.2
|
||||||
|
|
||||||
|
Patches
|
||||||
|
-------
|
||||||
|
st-alpha-0.8.5.diff
|
||||||
|
st-font2-20190416-ba72400.diff
|
||||||
|
st-copyurl-0.8.4.diff
|
||||||
|
st-openclipboard-20190202-3be4cf1.diff
|
||||||
|
st-appsync-20200618-b27a383.diff
|
||||||
|
st-xresources-20200604-9ba7ecf.diff
|
||||||
|
st-scrollback-20210507-4536f46.diff
|
||||||
|
st-scrollback-mouse-20191024-a2c479c.diff
|
||||||
|
st-scrollback-mouse-altscreen-20200416-5703aa0.diff
|
||||||
|
st-w3m-0.8.3.diff
|
||||||
|
st-keyboard_select-20200617-9ba7ecf.diff
|
||||||
|
st-boxdraw_v2-0.8.3.diff
|
||||||
|
|
||||||
|
Key - Bindings
|
||||||
|
--------------
|
||||||
|
Zoom - ctrl + plus, minus, equel (shift + mouse scroll)
|
||||||
|
Scollback - shift + page_up, page_down (mouse scroll)
|
||||||
|
Copy URL - alt + y
|
||||||
|
Open Copied URL - alt + o
|
||||||
|
Keyboard Select - ctrl + shift + esc
|
||||||
|
|
||||||
|
Keyboard Select - Navigation
|
||||||
|
----------------------------
|
||||||
|
h, j, k, l: move cursor left/down/up/right (also with arrow keys)
|
||||||
|
!, _, *: move cursor to the middle of the line/column/screen
|
||||||
|
Backspace, $: move cursor to the beginning/end of the line
|
||||||
|
PgUp, PgDown : move cursor to the beginning/end of the column
|
||||||
|
Home, End: move cursor to the top/bottom left corner of the screen
|
||||||
|
/, ?: activate input mode and search up/down
|
||||||
|
n, N: repeat last search, up/down
|
||||||
|
s: toggle move/selection mode
|
||||||
|
t: toggle regular/rectangular selection type
|
||||||
|
Return: quit keyboard_select, keeping the highlight of the selection
|
||||||
|
Escape: quit keyboard_select
|
||||||
|
|
||||||
|
Last implemented commit
|
||||||
|
-----------------------
|
||||||
|
2025-01-26 12:40 Do not interpret CSI ? u as DECRC Johannes Altmanninger
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
vt emulation
|
||||||
|
------------
|
||||||
|
|
||||||
|
* double-height support
|
||||||
|
|
||||||
|
code & interface
|
||||||
|
----------------
|
||||||
|
|
||||||
|
* add a simple way to do multiplexing
|
||||||
|
|
||||||
|
drawing
|
||||||
|
-------
|
||||||
|
* add diacritics support to xdraws()
|
||||||
|
* switch to a suckless font drawing library
|
||||||
|
* make the font cache simpler
|
||||||
|
* add better support for brightening of the upper colors
|
||||||
|
|
||||||
|
bugs
|
||||||
|
----
|
||||||
|
|
||||||
|
* fix shift up/down (shift selection in emacs)
|
||||||
|
* remove DEC test sequence when appropriate
|
||||||
|
|
||||||
|
misc
|
||||||
|
----
|
||||||
|
|
||||||
|
$ grep -nE 'XXX|TODO' st.c
|
||||||
|
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copy me if you can.
|
||||||
|
* by 20h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef ARG_H__
|
||||||
|
#define ARG_H__
|
||||||
|
|
||||||
|
extern char *argv0;
|
||||||
|
|
||||||
|
/* use main(int argc, char *argv[]) */
|
||||||
|
#define ARGBEGIN for (argv0 = *argv, argv++, argc--;\
|
||||||
|
argv[0] && argv[0][0] == '-'\
|
||||||
|
&& argv[0][1];\
|
||||||
|
argc--, argv++) {\
|
||||||
|
char argc_;\
|
||||||
|
char **argv_;\
|
||||||
|
int brk_;\
|
||||||
|
if (argv[0][1] == '-' && argv[0][2] == '\0') {\
|
||||||
|
argv++;\
|
||||||
|
argc--;\
|
||||||
|
break;\
|
||||||
|
}\
|
||||||
|
int i_;\
|
||||||
|
for (i_ = 1, brk_ = 0, argv_ = argv;\
|
||||||
|
argv[0][i_] && !brk_;\
|
||||||
|
i_++) {\
|
||||||
|
if (argv_ != argv)\
|
||||||
|
break;\
|
||||||
|
argc_ = argv[0][i_];\
|
||||||
|
switch (argc_)
|
||||||
|
|
||||||
|
#define ARGEND }\
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ARGC() argc_
|
||||||
|
|
||||||
|
#define EARGF(x) ((argv[0][i_+1] == '\0' && argv[1] == NULL)?\
|
||||||
|
((x), abort(), (char *)0) :\
|
||||||
|
(brk_ = 1, (argv[0][i_+1] != '\0')?\
|
||||||
|
(&argv[0][i_+1]) :\
|
||||||
|
(argc--, argv++, argv[0])))
|
||||||
|
|
||||||
|
#define ARGF() ((argv[0][i_+1] == '\0' && argv[1] == NULL)?\
|
||||||
|
(char *)0 :\
|
||||||
|
(brk_ = 1, (argv[0][i_+1] != '\0')?\
|
||||||
|
(&argv[0][i_+1]) :\
|
||||||
|
(argc--, argv++, argv[0])))
|
||||||
|
|
||||||
|
#endif
|
||||||
+194
@@ -0,0 +1,194 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Avi Halachmi (:avih) avihpit@yahoo.com https://github.com/avih
|
||||||
|
* MIT/X Consortium License
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <X11/Xft/Xft.h>
|
||||||
|
#include "st.h"
|
||||||
|
#include "boxdraw_data.h"
|
||||||
|
|
||||||
|
/* Rounded non-negative integers division of n / d */
|
||||||
|
#define DIV(n, d) (((n) + (d) / 2) / (d))
|
||||||
|
|
||||||
|
static Display *xdpy;
|
||||||
|
static Colormap xcmap;
|
||||||
|
static XftDraw *xd;
|
||||||
|
static Visual *xvis;
|
||||||
|
|
||||||
|
static void drawbox(int, int, int, int, XftColor *, XftColor *, ushort);
|
||||||
|
static void drawboxlines(int, int, int, int, XftColor *, ushort);
|
||||||
|
|
||||||
|
/* public API */
|
||||||
|
|
||||||
|
void
|
||||||
|
boxdraw_xinit(Display *dpy, Colormap cmap, XftDraw *draw, Visual *vis)
|
||||||
|
{
|
||||||
|
xdpy = dpy; xcmap = cmap; xd = draw, xvis = vis;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
isboxdraw(Rune u)
|
||||||
|
{
|
||||||
|
Rune block = u & ~0xff;
|
||||||
|
return (boxdraw && block == 0x2500 && boxdata[(uint8_t)u]) ||
|
||||||
|
(boxdraw_braille && block == 0x2800);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* the "index" is actually the entire shape data encoded as ushort */
|
||||||
|
ushort
|
||||||
|
boxdrawindex(const Glyph *g)
|
||||||
|
{
|
||||||
|
if (boxdraw_braille && (g->u & ~0xff) == 0x2800)
|
||||||
|
return BRL | (uint8_t)g->u;
|
||||||
|
if (boxdraw_bold && (g->mode & ATTR_BOLD))
|
||||||
|
return BDB | boxdata[(uint8_t)g->u];
|
||||||
|
return boxdata[(uint8_t)g->u];
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
drawboxes(int x, int y, int cw, int ch, XftColor *fg, XftColor *bg,
|
||||||
|
const XftGlyphFontSpec *specs, int len)
|
||||||
|
{
|
||||||
|
for ( ; len-- > 0; x += cw, specs++)
|
||||||
|
drawbox(x, y, cw, ch, fg, bg, (ushort)specs->glyph);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* implementation */
|
||||||
|
|
||||||
|
void
|
||||||
|
drawbox(int x, int y, int w, int h, XftColor *fg, XftColor *bg, ushort bd)
|
||||||
|
{
|
||||||
|
ushort cat = bd & ~(BDB | 0xff); /* mask out bold and data */
|
||||||
|
if (bd & (BDL | BDA)) {
|
||||||
|
/* lines (light/double/heavy/arcs) */
|
||||||
|
drawboxlines(x, y, w, h, fg, bd);
|
||||||
|
|
||||||
|
} else if (cat == BBD) {
|
||||||
|
/* lower (8-X)/8 block */
|
||||||
|
int d = DIV((uint8_t)bd * h, 8);
|
||||||
|
XftDrawRect(xd, fg, x, y + d, w, h - d);
|
||||||
|
|
||||||
|
} else if (cat == BBU) {
|
||||||
|
/* upper X/8 block */
|
||||||
|
XftDrawRect(xd, fg, x, y, w, DIV((uint8_t)bd * h, 8));
|
||||||
|
|
||||||
|
} else if (cat == BBL) {
|
||||||
|
/* left X/8 block */
|
||||||
|
XftDrawRect(xd, fg, x, y, DIV((uint8_t)bd * w, 8), h);
|
||||||
|
|
||||||
|
} else if (cat == BBR) {
|
||||||
|
/* right (8-X)/8 block */
|
||||||
|
int d = DIV((uint8_t)bd * w, 8);
|
||||||
|
XftDrawRect(xd, fg, x + d, y, w - d, h);
|
||||||
|
|
||||||
|
} else if (cat == BBQ) {
|
||||||
|
/* Quadrants */
|
||||||
|
int w2 = DIV(w, 2), h2 = DIV(h, 2);
|
||||||
|
if (bd & TL)
|
||||||
|
XftDrawRect(xd, fg, x, y, w2, h2);
|
||||||
|
if (bd & TR)
|
||||||
|
XftDrawRect(xd, fg, x + w2, y, w - w2, h2);
|
||||||
|
if (bd & BL)
|
||||||
|
XftDrawRect(xd, fg, x, y + h2, w2, h - h2);
|
||||||
|
if (bd & BR)
|
||||||
|
XftDrawRect(xd, fg, x + w2, y + h2, w - w2, h - h2);
|
||||||
|
|
||||||
|
} else if (bd & BBS) {
|
||||||
|
/* Shades - data is 1/2/3 for 25%/50%/75% alpha, respectively */
|
||||||
|
int d = (uint8_t)bd;
|
||||||
|
XftColor xfc;
|
||||||
|
XRenderColor xrc = { .alpha = 0xffff };
|
||||||
|
|
||||||
|
xrc.red = DIV(fg->color.red * d + bg->color.red * (4 - d), 4);
|
||||||
|
xrc.green = DIV(fg->color.green * d + bg->color.green * (4 - d), 4);
|
||||||
|
xrc.blue = DIV(fg->color.blue * d + bg->color.blue * (4 - d), 4);
|
||||||
|
|
||||||
|
XftColorAllocValue(xdpy, xvis, xcmap, &xrc, &xfc);
|
||||||
|
XftDrawRect(xd, &xfc, x, y, w, h);
|
||||||
|
XftColorFree(xdpy, xvis, xcmap, &xfc);
|
||||||
|
|
||||||
|
} else if (cat == BRL) {
|
||||||
|
/* braille, each data bit corresponds to one dot at 2x4 grid */
|
||||||
|
int w1 = DIV(w, 2);
|
||||||
|
int h1 = DIV(h, 4), h2 = DIV(h, 2), h3 = DIV(3 * h, 4);
|
||||||
|
|
||||||
|
if (bd & 1) XftDrawRect(xd, fg, x, y, w1, h1);
|
||||||
|
if (bd & 2) XftDrawRect(xd, fg, x, y + h1, w1, h2 - h1);
|
||||||
|
if (bd & 4) XftDrawRect(xd, fg, x, y + h2, w1, h3 - h2);
|
||||||
|
if (bd & 8) XftDrawRect(xd, fg, x + w1, y, w - w1, h1);
|
||||||
|
if (bd & 16) XftDrawRect(xd, fg, x + w1, y + h1, w - w1, h2 - h1);
|
||||||
|
if (bd & 32) XftDrawRect(xd, fg, x + w1, y + h2, w - w1, h3 - h2);
|
||||||
|
if (bd & 64) XftDrawRect(xd, fg, x, y + h3, w1, h - h3);
|
||||||
|
if (bd & 128) XftDrawRect(xd, fg, x + w1, y + h3, w - w1, h - h3);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
drawboxlines(int x, int y, int w, int h, XftColor *fg, ushort bd)
|
||||||
|
{
|
||||||
|
/* s: stem thickness. width/8 roughly matches underscore thickness. */
|
||||||
|
/* We draw bold as 1.5 * normal-stem and at least 1px thicker. */
|
||||||
|
/* doubles draw at least 3px, even when w or h < 3. bold needs 6px. */
|
||||||
|
int mwh = MIN(w, h);
|
||||||
|
int base_s = MAX(1, DIV(mwh, 8));
|
||||||
|
int bold = (bd & BDB) && mwh >= 6; /* possibly ignore boldness */
|
||||||
|
int s = bold ? MAX(base_s + 1, DIV(3 * base_s, 2)) : base_s;
|
||||||
|
int w2 = DIV(w - s, 2), h2 = DIV(h - s, 2);
|
||||||
|
/* the s-by-s square (x + w2, y + h2, s, s) is the center texel. */
|
||||||
|
/* The base length (per direction till edge) includes this square. */
|
||||||
|
|
||||||
|
int light = bd & (LL | LU | LR | LD);
|
||||||
|
int double_ = bd & (DL | DU | DR | DD);
|
||||||
|
|
||||||
|
if (light) {
|
||||||
|
/* d: additional (negative) length to not-draw the center */
|
||||||
|
/* texel - at arcs and avoid drawing inside (some) doubles */
|
||||||
|
int arc = bd & BDA;
|
||||||
|
int multi_light = light & (light - 1);
|
||||||
|
int multi_double = double_ & (double_ - 1);
|
||||||
|
/* light crosses double only at DH+LV, DV+LH (ref. shapes) */
|
||||||
|
int d = arc || (multi_double && !multi_light) ? -s : 0;
|
||||||
|
|
||||||
|
if (bd & LL)
|
||||||
|
XftDrawRect(xd, fg, x, y + h2, w2 + s + d, s);
|
||||||
|
if (bd & LU)
|
||||||
|
XftDrawRect(xd, fg, x + w2, y, s, h2 + s + d);
|
||||||
|
if (bd & LR)
|
||||||
|
XftDrawRect(xd, fg, x + w2 - d, y + h2, w - w2 + d, s);
|
||||||
|
if (bd & LD)
|
||||||
|
XftDrawRect(xd, fg, x + w2, y + h2 - d, s, h - h2 + d);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* double lines - also align with light to form heavy when combined */
|
||||||
|
if (double_) {
|
||||||
|
/*
|
||||||
|
* going clockwise, for each double-ray: p is additional length
|
||||||
|
* to the single-ray nearer to the previous direction, and n to
|
||||||
|
* the next. p and n adjust from the base length to lengths
|
||||||
|
* which consider other doubles - shorter to avoid intersections
|
||||||
|
* (p, n), or longer to draw the far-corner texel (n).
|
||||||
|
*/
|
||||||
|
int dl = bd & DL, du = bd & DU, dr = bd & DR, dd = bd & DD;
|
||||||
|
if (dl) {
|
||||||
|
int p = dd ? -s : 0, n = du ? -s : dd ? s : 0;
|
||||||
|
XftDrawRect(xd, fg, x, y + h2 + s, w2 + s + p, s);
|
||||||
|
XftDrawRect(xd, fg, x, y + h2 - s, w2 + s + n, s);
|
||||||
|
}
|
||||||
|
if (du) {
|
||||||
|
int p = dl ? -s : 0, n = dr ? -s : dl ? s : 0;
|
||||||
|
XftDrawRect(xd, fg, x + w2 - s, y, s, h2 + s + p);
|
||||||
|
XftDrawRect(xd, fg, x + w2 + s, y, s, h2 + s + n);
|
||||||
|
}
|
||||||
|
if (dr) {
|
||||||
|
int p = du ? -s : 0, n = dd ? -s : du ? s : 0;
|
||||||
|
XftDrawRect(xd, fg, x + w2 - p, y + h2 - s, w - w2 + p, s);
|
||||||
|
XftDrawRect(xd, fg, x + w2 - n, y + h2 + s, w - w2 + n, s);
|
||||||
|
}
|
||||||
|
if (dd) {
|
||||||
|
int p = dr ? -s : 0, n = dl ? -s : dr ? s : 0;
|
||||||
|
XftDrawRect(xd, fg, x + w2 + s, y + h2 - p, s, h - h2 + p);
|
||||||
|
XftDrawRect(xd, fg, x + w2 - s, y + h2 - n, s, h - h2 + n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,214 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Avi Halachmi (:avih) avihpit@yahoo.com https://github.com/avih
|
||||||
|
* MIT/X Consortium License
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* U+25XX codepoints data
|
||||||
|
*
|
||||||
|
* References:
|
||||||
|
* http://www.unicode.org/charts/PDF/U2500.pdf
|
||||||
|
* http://www.unicode.org/charts/PDF/U2580.pdf
|
||||||
|
*
|
||||||
|
* Test page:
|
||||||
|
* https://github.com/GNOME/vte/blob/master/doc/boxes.txt
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Each shape is encoded as 16-bits. Higher bits are category, lower are data */
|
||||||
|
/* Categories (mutually exclusive except BDB): */
|
||||||
|
/* For convenience, BDL/BDA/BBS/BDB are 1 bit each, the rest are enums */
|
||||||
|
#define BDL (1<<8) /* Box Draw Lines (light/double/heavy) */
|
||||||
|
#define BDA (1<<9) /* Box Draw Arc (light) */
|
||||||
|
|
||||||
|
#define BBD (1<<10) /* Box Block Down (lower) X/8 */
|
||||||
|
#define BBL (2<<10) /* Box Block Left X/8 */
|
||||||
|
#define BBU (3<<10) /* Box Block Upper X/8 */
|
||||||
|
#define BBR (4<<10) /* Box Block Right X/8 */
|
||||||
|
#define BBQ (5<<10) /* Box Block Quadrants */
|
||||||
|
#define BRL (6<<10) /* Box Braille (data is lower byte of U28XX) */
|
||||||
|
|
||||||
|
#define BBS (1<<14) /* Box Block Shades */
|
||||||
|
#define BDB (1<<15) /* Box Draw is Bold */
|
||||||
|
|
||||||
|
/* (BDL/BDA) Light/Double/Heavy x Left/Up/Right/Down/Horizontal/Vertical */
|
||||||
|
/* Heavy is light+double (literally drawing light+double align to form heavy) */
|
||||||
|
#define LL (1<<0)
|
||||||
|
#define LU (1<<1)
|
||||||
|
#define LR (1<<2)
|
||||||
|
#define LD (1<<3)
|
||||||
|
#define LH (LL+LR)
|
||||||
|
#define LV (LU+LD)
|
||||||
|
|
||||||
|
#define DL (1<<4)
|
||||||
|
#define DU (1<<5)
|
||||||
|
#define DR (1<<6)
|
||||||
|
#define DD (1<<7)
|
||||||
|
#define DH (DL+DR)
|
||||||
|
#define DV (DU+DD)
|
||||||
|
|
||||||
|
#define HL (LL+DL)
|
||||||
|
#define HU (LU+DU)
|
||||||
|
#define HR (LR+DR)
|
||||||
|
#define HD (LD+DD)
|
||||||
|
#define HH (HL+HR)
|
||||||
|
#define HV (HU+HD)
|
||||||
|
|
||||||
|
/* (BBQ) Quadrants Top/Bottom x Left/Right */
|
||||||
|
#define TL (1<<0)
|
||||||
|
#define TR (1<<1)
|
||||||
|
#define BL (1<<2)
|
||||||
|
#define BR (1<<3)
|
||||||
|
|
||||||
|
/* Data for U+2500 - U+259F except dashes/diagonals */
|
||||||
|
static const unsigned short boxdata[256] = {
|
||||||
|
/* light lines */
|
||||||
|
[0x00] = BDL + LH, /* light horizontal */
|
||||||
|
[0x02] = BDL + LV, /* light vertical */
|
||||||
|
[0x0c] = BDL + LD + LR, /* light down and right */
|
||||||
|
[0x10] = BDL + LD + LL, /* light down and left */
|
||||||
|
[0x14] = BDL + LU + LR, /* light up and right */
|
||||||
|
[0x18] = BDL + LU + LL, /* light up and left */
|
||||||
|
[0x1c] = BDL + LV + LR, /* light vertical and right */
|
||||||
|
[0x24] = BDL + LV + LL, /* light vertical and left */
|
||||||
|
[0x2c] = BDL + LH + LD, /* light horizontal and down */
|
||||||
|
[0x34] = BDL + LH + LU, /* light horizontal and up */
|
||||||
|
[0x3c] = BDL + LV + LH, /* light vertical and horizontal */
|
||||||
|
[0x74] = BDL + LL, /* light left */
|
||||||
|
[0x75] = BDL + LU, /* light up */
|
||||||
|
[0x76] = BDL + LR, /* light right */
|
||||||
|
[0x77] = BDL + LD, /* light down */
|
||||||
|
|
||||||
|
/* heavy [+light] lines */
|
||||||
|
[0x01] = BDL + HH,
|
||||||
|
[0x03] = BDL + HV,
|
||||||
|
[0x0d] = BDL + HR + LD,
|
||||||
|
[0x0e] = BDL + HD + LR,
|
||||||
|
[0x0f] = BDL + HD + HR,
|
||||||
|
[0x11] = BDL + HL + LD,
|
||||||
|
[0x12] = BDL + HD + LL,
|
||||||
|
[0x13] = BDL + HD + HL,
|
||||||
|
[0x15] = BDL + HR + LU,
|
||||||
|
[0x16] = BDL + HU + LR,
|
||||||
|
[0x17] = BDL + HU + HR,
|
||||||
|
[0x19] = BDL + HL + LU,
|
||||||
|
[0x1a] = BDL + HU + LL,
|
||||||
|
[0x1b] = BDL + HU + HL,
|
||||||
|
[0x1d] = BDL + HR + LV,
|
||||||
|
[0x1e] = BDL + HU + LD + LR,
|
||||||
|
[0x1f] = BDL + HD + LR + LU,
|
||||||
|
[0x20] = BDL + HV + LR,
|
||||||
|
[0x21] = BDL + HU + HR + LD,
|
||||||
|
[0x22] = BDL + HD + HR + LU,
|
||||||
|
[0x23] = BDL + HV + HR,
|
||||||
|
[0x25] = BDL + HL + LV,
|
||||||
|
[0x26] = BDL + HU + LD + LL,
|
||||||
|
[0x27] = BDL + HD + LU + LL,
|
||||||
|
[0x28] = BDL + HV + LL,
|
||||||
|
[0x29] = BDL + HU + HL + LD,
|
||||||
|
[0x2a] = BDL + HD + HL + LU,
|
||||||
|
[0x2b] = BDL + HV + HL,
|
||||||
|
[0x2d] = BDL + HL + LD + LR,
|
||||||
|
[0x2e] = BDL + HR + LL + LD,
|
||||||
|
[0x2f] = BDL + HH + LD,
|
||||||
|
[0x30] = BDL + HD + LH,
|
||||||
|
[0x31] = BDL + HD + HL + LR,
|
||||||
|
[0x32] = BDL + HR + HD + LL,
|
||||||
|
[0x33] = BDL + HH + HD,
|
||||||
|
[0x35] = BDL + HL + LU + LR,
|
||||||
|
[0x36] = BDL + HR + LU + LL,
|
||||||
|
[0x37] = BDL + HH + LU,
|
||||||
|
[0x38] = BDL + HU + LH,
|
||||||
|
[0x39] = BDL + HU + HL + LR,
|
||||||
|
[0x3a] = BDL + HU + HR + LL,
|
||||||
|
[0x3b] = BDL + HH + HU,
|
||||||
|
[0x3d] = BDL + HL + LV + LR,
|
||||||
|
[0x3e] = BDL + HR + LV + LL,
|
||||||
|
[0x3f] = BDL + HH + LV,
|
||||||
|
[0x40] = BDL + HU + LH + LD,
|
||||||
|
[0x41] = BDL + HD + LH + LU,
|
||||||
|
[0x42] = BDL + HV + LH,
|
||||||
|
[0x43] = BDL + HU + HL + LD + LR,
|
||||||
|
[0x44] = BDL + HU + HR + LD + LL,
|
||||||
|
[0x45] = BDL + HD + HL + LU + LR,
|
||||||
|
[0x46] = BDL + HD + HR + LU + LL,
|
||||||
|
[0x47] = BDL + HH + HU + LD,
|
||||||
|
[0x48] = BDL + HH + HD + LU,
|
||||||
|
[0x49] = BDL + HV + HL + LR,
|
||||||
|
[0x4a] = BDL + HV + HR + LL,
|
||||||
|
[0x4b] = BDL + HV + HH,
|
||||||
|
[0x78] = BDL + HL,
|
||||||
|
[0x79] = BDL + HU,
|
||||||
|
[0x7a] = BDL + HR,
|
||||||
|
[0x7b] = BDL + HD,
|
||||||
|
[0x7c] = BDL + HR + LL,
|
||||||
|
[0x7d] = BDL + HD + LU,
|
||||||
|
[0x7e] = BDL + HL + LR,
|
||||||
|
[0x7f] = BDL + HU + LD,
|
||||||
|
|
||||||
|
/* double [+light] lines */
|
||||||
|
[0x50] = BDL + DH,
|
||||||
|
[0x51] = BDL + DV,
|
||||||
|
[0x52] = BDL + DR + LD,
|
||||||
|
[0x53] = BDL + DD + LR,
|
||||||
|
[0x54] = BDL + DR + DD,
|
||||||
|
[0x55] = BDL + DL + LD,
|
||||||
|
[0x56] = BDL + DD + LL,
|
||||||
|
[0x57] = BDL + DL + DD,
|
||||||
|
[0x58] = BDL + DR + LU,
|
||||||
|
[0x59] = BDL + DU + LR,
|
||||||
|
[0x5a] = BDL + DU + DR,
|
||||||
|
[0x5b] = BDL + DL + LU,
|
||||||
|
[0x5c] = BDL + DU + LL,
|
||||||
|
[0x5d] = BDL + DL + DU,
|
||||||
|
[0x5e] = BDL + DR + LV,
|
||||||
|
[0x5f] = BDL + DV + LR,
|
||||||
|
[0x60] = BDL + DV + DR,
|
||||||
|
[0x61] = BDL + DL + LV,
|
||||||
|
[0x62] = BDL + DV + LL,
|
||||||
|
[0x63] = BDL + DV + DL,
|
||||||
|
[0x64] = BDL + DH + LD,
|
||||||
|
[0x65] = BDL + DD + LH,
|
||||||
|
[0x66] = BDL + DD + DH,
|
||||||
|
[0x67] = BDL + DH + LU,
|
||||||
|
[0x68] = BDL + DU + LH,
|
||||||
|
[0x69] = BDL + DH + DU,
|
||||||
|
[0x6a] = BDL + DH + LV,
|
||||||
|
[0x6b] = BDL + DV + LH,
|
||||||
|
[0x6c] = BDL + DH + DV,
|
||||||
|
|
||||||
|
/* (light) arcs */
|
||||||
|
[0x6d] = BDA + LD + LR,
|
||||||
|
[0x6e] = BDA + LD + LL,
|
||||||
|
[0x6f] = BDA + LU + LL,
|
||||||
|
[0x70] = BDA + LU + LR,
|
||||||
|
|
||||||
|
/* Lower (Down) X/8 block (data is 8 - X) */
|
||||||
|
[0x81] = BBD + 7, [0x82] = BBD + 6, [0x83] = BBD + 5, [0x84] = BBD + 4,
|
||||||
|
[0x85] = BBD + 3, [0x86] = BBD + 2, [0x87] = BBD + 1, [0x88] = BBD + 0,
|
||||||
|
|
||||||
|
/* Left X/8 block (data is X) */
|
||||||
|
[0x89] = BBL + 7, [0x8a] = BBL + 6, [0x8b] = BBL + 5, [0x8c] = BBL + 4,
|
||||||
|
[0x8d] = BBL + 3, [0x8e] = BBL + 2, [0x8f] = BBL + 1,
|
||||||
|
|
||||||
|
/* upper 1/2 (4/8), 1/8 block (X), right 1/2, 1/8 block (8-X) */
|
||||||
|
[0x80] = BBU + 4, [0x94] = BBU + 1,
|
||||||
|
[0x90] = BBR + 4, [0x95] = BBR + 7,
|
||||||
|
|
||||||
|
/* Quadrants */
|
||||||
|
[0x96] = BBQ + BL,
|
||||||
|
[0x97] = BBQ + BR,
|
||||||
|
[0x98] = BBQ + TL,
|
||||||
|
[0x99] = BBQ + TL + BL + BR,
|
||||||
|
[0x9a] = BBQ + TL + BR,
|
||||||
|
[0x9b] = BBQ + TL + TR + BL,
|
||||||
|
[0x9c] = BBQ + TL + TR + BR,
|
||||||
|
[0x9d] = BBQ + TR,
|
||||||
|
[0x9e] = BBQ + BL + TR,
|
||||||
|
[0x9f] = BBQ + BL + TR + BR,
|
||||||
|
|
||||||
|
/* Shades, data is an alpha value in 25% units (1/4, 1/2, 3/4) */
|
||||||
|
[0x91] = BBS + 1, [0x92] = BBS + 2, [0x93] = BBS + 3,
|
||||||
|
|
||||||
|
/* U+2504 - U+250B, U+254C - U+254F: unsupported (dashes) */
|
||||||
|
/* U+2571 - U+2573: unsupported (diagonals) */
|
||||||
|
};
|
||||||
+547
@@ -0,0 +1,547 @@
|
|||||||
|
/* See LICENSE file for copyright and license details. */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* appearance
|
||||||
|
*
|
||||||
|
* font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html
|
||||||
|
*/
|
||||||
|
static char *font = "DejaVu Sans Mono:pixelsize=16";
|
||||||
|
/* Spare fonts */
|
||||||
|
static char *font2[] = {
|
||||||
|
"DejaVu Sans:pixelsize=16",
|
||||||
|
"DejaVuSansM Nerd Font:pixelsize=16",
|
||||||
|
"Noto Color Emoji:pixelsize=14"
|
||||||
|
};
|
||||||
|
|
||||||
|
static int borderpx = 2;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* What program is execed by st depends of these precedence rules:
|
||||||
|
* 1: program passed with -e
|
||||||
|
* 2: scroll and/or utmp
|
||||||
|
* 3: SHELL environment variable
|
||||||
|
* 4: value of shell in /etc/passwd
|
||||||
|
* 5: value of shell in config.h
|
||||||
|
*/
|
||||||
|
static char *shell = "/bin/sh";
|
||||||
|
char *utmp = NULL;
|
||||||
|
/* scroll program: to enable use a string like "scroll" */
|
||||||
|
char *scroll = NULL;
|
||||||
|
char *stty_args = "stty raw pass8 nl -echo -iexten -cstopb 38400";
|
||||||
|
|
||||||
|
/* identification sequence returned in DA and DECID */
|
||||||
|
char *vtiden = "\033[?6c";
|
||||||
|
|
||||||
|
/* Kerning / character bounding-box multipliers */
|
||||||
|
static float cwscale = 1.0;
|
||||||
|
static float chscale = 1.0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* word delimiter string
|
||||||
|
*
|
||||||
|
* More advanced example: L" `'\"()[]{}"
|
||||||
|
*/
|
||||||
|
wchar_t *worddelimiters = L" ";
|
||||||
|
|
||||||
|
/* selection timeouts (in milliseconds) */
|
||||||
|
static unsigned int doubleclicktimeout = 300;
|
||||||
|
static unsigned int tripleclicktimeout = 600;
|
||||||
|
|
||||||
|
/* alt screens */
|
||||||
|
int allowaltscreen = 1;
|
||||||
|
|
||||||
|
/* allow certain non-interactive (insecure) window operations such as:
|
||||||
|
setting the clipboard text */
|
||||||
|
int allowwindowops = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* draw latency range in ms - from new content/keypress/etc until drawing.
|
||||||
|
* within this range, st draws when content stops arriving (idle). mostly it's
|
||||||
|
* near minlatency, but it waits longer for slow updates to avoid partial draw.
|
||||||
|
* low minlatency will tear/flicker more, as it can "detect" idle too early.
|
||||||
|
*/
|
||||||
|
static double minlatency = 2;
|
||||||
|
static double maxlatency = 33;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Synchronized-Update timeout in ms
|
||||||
|
* https://gitlab.com/gnachman/iterm2/-/wikis/synchronized-updates-spec
|
||||||
|
*/
|
||||||
|
static uint su_timeout = 200;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* blinking timeout (set to 0 to disable blinking) for the terminal blinking
|
||||||
|
* attribute.
|
||||||
|
*/
|
||||||
|
static unsigned int blinktimeout = 800;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* thickness of underline and bar cursors
|
||||||
|
*/
|
||||||
|
static unsigned int cursorthickness = 2;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 1: render most of the lines/blocks characters without using the font for
|
||||||
|
* perfect alignment between cells (U2500 - U259F except dashes/diagonals).
|
||||||
|
* Bold affects lines thickness if boxdraw_bold is not 0. Italic is ignored.
|
||||||
|
* 0: disable (render all U25XX glyphs normally from the font).
|
||||||
|
*/
|
||||||
|
const int boxdraw = 1;
|
||||||
|
const int boxdraw_bold = 0;
|
||||||
|
|
||||||
|
/* braille (U28XX): 1: render as adjacent "pixels", 0: use font */
|
||||||
|
const int boxdraw_braille = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* bell volume. It must be a value between -100 and 100. Use 0 for disabling
|
||||||
|
* it
|
||||||
|
*/
|
||||||
|
static int bellvolume = 0;
|
||||||
|
|
||||||
|
/* default TERM value */
|
||||||
|
char *termname = "st-256color";
|
||||||
|
|
||||||
|
/*
|
||||||
|
* spaces per tab
|
||||||
|
*
|
||||||
|
* When you are changing this value, don't forget to adapt the »it« value in
|
||||||
|
* the st.info and appropriately install the st.info in the environment where
|
||||||
|
* you use this st version.
|
||||||
|
*
|
||||||
|
* it#$tabspaces,
|
||||||
|
*
|
||||||
|
* Secondly make sure your kernel is not expanding tabs. When running `stty
|
||||||
|
* -a` »tab0« should appear. You can tell the terminal to not expand tabs by
|
||||||
|
* running following command:
|
||||||
|
*
|
||||||
|
* stty tabs
|
||||||
|
*/
|
||||||
|
unsigned int tabspaces = 8;
|
||||||
|
|
||||||
|
/* bg opacity */
|
||||||
|
float alpha = 0.9;
|
||||||
|
|
||||||
|
/* Terminal colors (16 first used in escape sequence) */
|
||||||
|
static const char *colorname[] = {
|
||||||
|
/* 8 normal colors */
|
||||||
|
"#000000", /* 0 -> black */
|
||||||
|
"#df2800", /* 1 -> red */
|
||||||
|
"#00b200", /* 2 -> green */
|
||||||
|
"#b0b200", /* 3 -> yellow */
|
||||||
|
"#1f5393", /* 4 -> blue */
|
||||||
|
"#980096", /* 5 -> magenta */
|
||||||
|
"#008081", /* 6 -> cyan */
|
||||||
|
"#cccccc", /* 7 -> white */
|
||||||
|
|
||||||
|
/* 8 bright colors */
|
||||||
|
"#333333", /* 8 -> black */
|
||||||
|
"#ff5555", /* 9 -> red */
|
||||||
|
"#39ff14", /* 10 -> green */
|
||||||
|
"#effd5f", /* 11 -> yellow */
|
||||||
|
"#4185d7", /* 12 -> blue */
|
||||||
|
"#ff6fff", /* 13 -> magenta */
|
||||||
|
"#7ef9ff", /* 14 -> cyan */
|
||||||
|
"#ffffff", /* 15 -> white */
|
||||||
|
|
||||||
|
[255] = 0,
|
||||||
|
|
||||||
|
/* more colors can be added after 255 to use with DefaultXX */
|
||||||
|
"#000000", /* 256 -> bg */
|
||||||
|
"#ffffff", /* 257 -> fg */
|
||||||
|
"#4185d7", /* 258 -> cursor */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Default colors (colorname index)
|
||||||
|
* foreground, background, cursor, reverse cursor
|
||||||
|
*/
|
||||||
|
unsigned int defaultfg = 257;
|
||||||
|
unsigned int defaultbg = 256;
|
||||||
|
unsigned int defaultcs = 258;
|
||||||
|
static unsigned int defaultrcs = 256;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Default shape of cursor
|
||||||
|
* 2: Block ("█")
|
||||||
|
* 4: Underline ("_")
|
||||||
|
* 6: Bar ("|")
|
||||||
|
* 7: Snowman ("☃")
|
||||||
|
*/
|
||||||
|
static unsigned int cursorshape = 2;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Default columns and rows numbers
|
||||||
|
*/
|
||||||
|
|
||||||
|
static unsigned int cols = 80;
|
||||||
|
static unsigned int rows = 24;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Default colour and shape of the mouse cursor
|
||||||
|
*/
|
||||||
|
static unsigned int mouseshape = XC_xterm;
|
||||||
|
static unsigned int mousefg = 7;
|
||||||
|
static unsigned int mousebg = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Color used to display font attributes when fontconfig selected a font which
|
||||||
|
* doesn't match the ones requested.
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Xresources preferences to load at startup
|
||||||
|
*/
|
||||||
|
ResourcePref resources[] = {
|
||||||
|
{ "font", STRING, &font },
|
||||||
|
{ "font0", STRING, &font2[0] },
|
||||||
|
{ "font1", STRING, &font2[1] },
|
||||||
|
{ "font2", STRING, &font2[2] },
|
||||||
|
{ "color0", STRING, &colorname[0] },
|
||||||
|
{ "color1", STRING, &colorname[1] },
|
||||||
|
{ "color2", STRING, &colorname[2] },
|
||||||
|
{ "color3", STRING, &colorname[3] },
|
||||||
|
{ "color4", STRING, &colorname[4] },
|
||||||
|
{ "color5", STRING, &colorname[5] },
|
||||||
|
{ "color6", STRING, &colorname[6] },
|
||||||
|
{ "color7", STRING, &colorname[7] },
|
||||||
|
{ "color8", STRING, &colorname[8] },
|
||||||
|
{ "color9", STRING, &colorname[9] },
|
||||||
|
{ "color10", STRING, &colorname[10] },
|
||||||
|
{ "color11", STRING, &colorname[11] },
|
||||||
|
{ "color12", STRING, &colorname[12] },
|
||||||
|
{ "color13", STRING, &colorname[13] },
|
||||||
|
{ "color14", STRING, &colorname[14] },
|
||||||
|
{ "color15", STRING, &colorname[15] },
|
||||||
|
{ "background", STRING, &colorname[256] },
|
||||||
|
{ "foreground", STRING, &colorname[257] },
|
||||||
|
{ "cursorColor", STRING, &colorname[258] },
|
||||||
|
{ "termname", STRING, &termname },
|
||||||
|
{ "shell", STRING, &shell },
|
||||||
|
{ "minlatency", FLOAT, &minlatency },
|
||||||
|
{ "maxlatency", FLOAT, &maxlatency },
|
||||||
|
{ "blinktimeout", INTEGER, &blinktimeout },
|
||||||
|
{ "bellvolume", INTEGER, &bellvolume },
|
||||||
|
{ "tabspaces", INTEGER, &tabspaces },
|
||||||
|
{ "borderpx", INTEGER, &borderpx },
|
||||||
|
{ "cwscale", FLOAT, &cwscale },
|
||||||
|
{ "chscale", FLOAT, &chscale },
|
||||||
|
{ "alpha", FLOAT, &alpha },
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Internal mouse shortcuts.
|
||||||
|
* Beware that overloading Button1 will disable the selection.
|
||||||
|
*/
|
||||||
|
static MouseShortcut mshortcuts[] = {
|
||||||
|
/* mask button function argument release */
|
||||||
|
{ XK_ANY_MOD, Button4, kscrollup, {.i = 5}, 0, /* !alt */ -1 },
|
||||||
|
{ XK_ANY_MOD, Button5, kscrolldown, {.i = 5}, 0, /* !alt */ -1 },
|
||||||
|
{ XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 },
|
||||||
|
{ ShiftMask, Button4, ttysend, {.s = "\033[5;2~"} },
|
||||||
|
{ XK_ANY_MOD, Button4, ttysend, {.s = "\031"} },
|
||||||
|
{ ShiftMask, Button5, ttysend, {.s = "\033[6;2~"} },
|
||||||
|
{ XK_ANY_MOD, Button5, ttysend, {.s = "\005"} },
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Internal keyboard shortcuts. */
|
||||||
|
#define MODKEY Mod1Mask
|
||||||
|
#define TERMMOD (ControlMask|ShiftMask)
|
||||||
|
|
||||||
|
static Shortcut shortcuts[] = {
|
||||||
|
/* mask keysym function argument */
|
||||||
|
{ XK_ANY_MOD, XK_Break, sendbreak, {.i = 0} },
|
||||||
|
{ ControlMask, XK_Print, toggleprinter, {.i = 0} },
|
||||||
|
{ ShiftMask, XK_Print, printscreen, {.i = 0} },
|
||||||
|
{ XK_ANY_MOD, XK_Print, printsel, {.i = 0} },
|
||||||
|
{ TERMMOD, XK_plus, zoom, {.f = +1} },
|
||||||
|
{ ControlMask, XK_minus, zoom, {.f = -1} },
|
||||||
|
{ ControlMask, XK_equal, zoomreset, {.f = 0} },
|
||||||
|
{ TERMMOD, XK_C, clipcopy, {.i = 0} },
|
||||||
|
{ TERMMOD, XK_V, clippaste, {.i = 0} },
|
||||||
|
{ TERMMOD, XK_Y, selpaste, {.i = 0} },
|
||||||
|
{ ShiftMask, XK_Insert, selpaste, {.i = 0} },
|
||||||
|
{ TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
|
||||||
|
{ MODKEY, XK_y, copyurl, {.i = 0} },
|
||||||
|
{ MODKEY, XK_o, opencopied, {.v = "link_handler.sh"} },
|
||||||
|
{ ShiftMask, XK_Page_Up, kscrollup, {.i = -1} },
|
||||||
|
{ ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} },
|
||||||
|
{ TERMMOD, XK_Escape, keyboard_select,{.i = 0} },
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Special keys (change & recompile st.info accordingly)
|
||||||
|
*
|
||||||
|
* Mask value:
|
||||||
|
* * Use XK_ANY_MOD to match the key no matter modifiers state
|
||||||
|
* * Use XK_NO_MOD to match the key alone (no modifiers)
|
||||||
|
* appkey value:
|
||||||
|
* * 0: no value
|
||||||
|
* * > 0: keypad application mode enabled
|
||||||
|
* * = 2: term.numlock = 1
|
||||||
|
* * < 0: keypad application mode disabled
|
||||||
|
* appcursor value:
|
||||||
|
* * 0: no value
|
||||||
|
* * > 0: cursor application mode enabled
|
||||||
|
* * < 0: cursor application mode disabled
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* position for a key.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If you want keys other than the X11 function keys (0xFD00 - 0xFFFF)
|
||||||
|
* to be mapped below, add them to this array.
|
||||||
|
*/
|
||||||
|
static KeySym mappedkeys[] = { -1 };
|
||||||
|
|
||||||
|
/*
|
||||||
|
* State bits to ignore when matching key or button events. By default,
|
||||||
|
* numlock (Mod2Mask) and keyboard layout (XK_SWITCH_MOD) are ignored.
|
||||||
|
*/
|
||||||
|
static uint ignoremod = Mod2Mask|XK_SWITCH_MOD;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is the huge key array which defines all compatibility to the Linux
|
||||||
|
* world. Please decide about changes wisely.
|
||||||
|
*/
|
||||||
|
static Key key[] = {
|
||||||
|
/* keysym mask string appkey appcursor */
|
||||||
|
{ XK_KP_Home, ShiftMask, "\033[2J", 0, -1},
|
||||||
|
{ XK_KP_Home, ShiftMask, "\033[1;2H", 0, +1},
|
||||||
|
{ XK_KP_Home, XK_ANY_MOD, "\033[H", 0, -1},
|
||||||
|
{ XK_KP_Home, XK_ANY_MOD, "\033[1~", 0, +1},
|
||||||
|
{ XK_KP_Up, XK_ANY_MOD, "\033Ox", +1, 0},
|
||||||
|
{ XK_KP_Up, XK_ANY_MOD, "\033[A", 0, -1},
|
||||||
|
{ XK_KP_Up, XK_ANY_MOD, "\033OA", 0, +1},
|
||||||
|
{ XK_KP_Down, XK_ANY_MOD, "\033Or", +1, 0},
|
||||||
|
{ XK_KP_Down, XK_ANY_MOD, "\033[B", 0, -1},
|
||||||
|
{ XK_KP_Down, XK_ANY_MOD, "\033OB", 0, +1},
|
||||||
|
{ XK_KP_Left, XK_ANY_MOD, "\033Ot", +1, 0},
|
||||||
|
{ XK_KP_Left, XK_ANY_MOD, "\033[D", 0, -1},
|
||||||
|
{ XK_KP_Left, XK_ANY_MOD, "\033OD", 0, +1},
|
||||||
|
{ XK_KP_Right, XK_ANY_MOD, "\033Ov", +1, 0},
|
||||||
|
{ XK_KP_Right, XK_ANY_MOD, "\033[C", 0, -1},
|
||||||
|
{ XK_KP_Right, XK_ANY_MOD, "\033OC", 0, +1},
|
||||||
|
{ XK_KP_Prior, ShiftMask, "\033[5;2~", 0, 0},
|
||||||
|
{ XK_KP_Prior, XK_ANY_MOD, "\033[5~", 0, 0},
|
||||||
|
{ XK_KP_Begin, XK_ANY_MOD, "\033[E", 0, 0},
|
||||||
|
{ XK_KP_End, ControlMask, "\033[J", -1, 0},
|
||||||
|
{ XK_KP_End, ControlMask, "\033[1;5F", +1, 0},
|
||||||
|
{ XK_KP_End, ShiftMask, "\033[K", -1, 0},
|
||||||
|
{ XK_KP_End, ShiftMask, "\033[1;2F", +1, 0},
|
||||||
|
{ XK_KP_End, XK_ANY_MOD, "\033[4~", 0, 0},
|
||||||
|
{ XK_KP_Next, ShiftMask, "\033[6;2~", 0, 0},
|
||||||
|
{ XK_KP_Next, XK_ANY_MOD, "\033[6~", 0, 0},
|
||||||
|
{ XK_KP_Insert, ShiftMask, "\033[2;2~", +1, 0},
|
||||||
|
{ XK_KP_Insert, ShiftMask, "\033[4l", -1, 0},
|
||||||
|
{ XK_KP_Insert, ControlMask, "\033[L", -1, 0},
|
||||||
|
{ XK_KP_Insert, ControlMask, "\033[2;5~", +1, 0},
|
||||||
|
{ XK_KP_Insert, XK_ANY_MOD, "\033[4h", -1, 0},
|
||||||
|
{ XK_KP_Insert, XK_ANY_MOD, "\033[2~", +1, 0},
|
||||||
|
{ XK_KP_Delete, ControlMask, "\033[M", -1, 0},
|
||||||
|
{ XK_KP_Delete, ControlMask, "\033[3;5~", +1, 0},
|
||||||
|
{ XK_KP_Delete, ShiftMask, "\033[2K", -1, 0},
|
||||||
|
{ XK_KP_Delete, ShiftMask, "\033[3;2~", +1, 0},
|
||||||
|
{ XK_KP_Delete, XK_ANY_MOD, "\033[P", -1, 0},
|
||||||
|
{ XK_KP_Delete, XK_ANY_MOD, "\033[3~", +1, 0},
|
||||||
|
{ XK_KP_Multiply, XK_ANY_MOD, "\033Oj", +2, 0},
|
||||||
|
{ XK_KP_Add, XK_ANY_MOD, "\033Ok", +2, 0},
|
||||||
|
{ XK_KP_Enter, XK_ANY_MOD, "\033OM", +2, 0},
|
||||||
|
{ XK_KP_Enter, XK_ANY_MOD, "\r", -1, 0},
|
||||||
|
{ XK_KP_Subtract, XK_ANY_MOD, "\033Om", +2, 0},
|
||||||
|
{ XK_KP_Decimal, XK_ANY_MOD, "\033On", +2, 0},
|
||||||
|
{ XK_KP_Divide, XK_ANY_MOD, "\033Oo", +2, 0},
|
||||||
|
{ XK_KP_0, XK_ANY_MOD, "\033Op", +2, 0},
|
||||||
|
{ XK_KP_1, XK_ANY_MOD, "\033Oq", +2, 0},
|
||||||
|
{ XK_KP_2, XK_ANY_MOD, "\033Or", +2, 0},
|
||||||
|
{ XK_KP_3, XK_ANY_MOD, "\033Os", +2, 0},
|
||||||
|
{ XK_KP_4, XK_ANY_MOD, "\033Ot", +2, 0},
|
||||||
|
{ XK_KP_5, XK_ANY_MOD, "\033Ou", +2, 0},
|
||||||
|
{ XK_KP_6, XK_ANY_MOD, "\033Ov", +2, 0},
|
||||||
|
{ XK_KP_7, XK_ANY_MOD, "\033Ow", +2, 0},
|
||||||
|
{ XK_KP_8, XK_ANY_MOD, "\033Ox", +2, 0},
|
||||||
|
{ XK_KP_9, XK_ANY_MOD, "\033Oy", +2, 0},
|
||||||
|
{ XK_Up, ShiftMask, "\033[1;2A", 0, 0},
|
||||||
|
{ XK_Up, Mod1Mask, "\033[1;3A", 0, 0},
|
||||||
|
{ XK_Up, ShiftMask|Mod1Mask,"\033[1;4A", 0, 0},
|
||||||
|
{ XK_Up, ControlMask, "\033[1;5A", 0, 0},
|
||||||
|
{ XK_Up, ShiftMask|ControlMask,"\033[1;6A", 0, 0},
|
||||||
|
{ XK_Up, ControlMask|Mod1Mask,"\033[1;7A", 0, 0},
|
||||||
|
{ XK_Up,ShiftMask|ControlMask|Mod1Mask,"\033[1;8A", 0, 0},
|
||||||
|
{ XK_Up, XK_ANY_MOD, "\033[A", 0, -1},
|
||||||
|
{ XK_Up, XK_ANY_MOD, "\033OA", 0, +1},
|
||||||
|
{ XK_Down, ShiftMask, "\033[1;2B", 0, 0},
|
||||||
|
{ XK_Down, Mod1Mask, "\033[1;3B", 0, 0},
|
||||||
|
{ XK_Down, ShiftMask|Mod1Mask,"\033[1;4B", 0, 0},
|
||||||
|
{ XK_Down, ControlMask, "\033[1;5B", 0, 0},
|
||||||
|
{ XK_Down, ShiftMask|ControlMask,"\033[1;6B", 0, 0},
|
||||||
|
{ XK_Down, ControlMask|Mod1Mask,"\033[1;7B", 0, 0},
|
||||||
|
{ XK_Down,ShiftMask|ControlMask|Mod1Mask,"\033[1;8B",0, 0},
|
||||||
|
{ XK_Down, XK_ANY_MOD, "\033[B", 0, -1},
|
||||||
|
{ XK_Down, XK_ANY_MOD, "\033OB", 0, +1},
|
||||||
|
{ XK_Left, ShiftMask, "\033[1;2D", 0, 0},
|
||||||
|
{ XK_Left, Mod1Mask, "\033[1;3D", 0, 0},
|
||||||
|
{ XK_Left, ShiftMask|Mod1Mask,"\033[1;4D", 0, 0},
|
||||||
|
{ XK_Left, ControlMask, "\033[1;5D", 0, 0},
|
||||||
|
{ XK_Left, ShiftMask|ControlMask,"\033[1;6D", 0, 0},
|
||||||
|
{ XK_Left, ControlMask|Mod1Mask,"\033[1;7D", 0, 0},
|
||||||
|
{ XK_Left,ShiftMask|ControlMask|Mod1Mask,"\033[1;8D",0, 0},
|
||||||
|
{ XK_Left, XK_ANY_MOD, "\033[D", 0, -1},
|
||||||
|
{ XK_Left, XK_ANY_MOD, "\033OD", 0, +1},
|
||||||
|
{ XK_Right, ShiftMask, "\033[1;2C", 0, 0},
|
||||||
|
{ XK_Right, Mod1Mask, "\033[1;3C", 0, 0},
|
||||||
|
{ XK_Right, ShiftMask|Mod1Mask,"\033[1;4C", 0, 0},
|
||||||
|
{ XK_Right, ControlMask, "\033[1;5C", 0, 0},
|
||||||
|
{ XK_Right, ShiftMask|ControlMask,"\033[1;6C", 0, 0},
|
||||||
|
{ XK_Right, ControlMask|Mod1Mask,"\033[1;7C", 0, 0},
|
||||||
|
{ XK_Right,ShiftMask|ControlMask|Mod1Mask,"\033[1;8C",0, 0},
|
||||||
|
{ XK_Right, XK_ANY_MOD, "\033[C", 0, -1},
|
||||||
|
{ XK_Right, XK_ANY_MOD, "\033OC", 0, +1},
|
||||||
|
{ XK_ISO_Left_Tab, ShiftMask, "\033[Z", 0, 0},
|
||||||
|
{ XK_Return, Mod1Mask, "\033\r", 0, 0},
|
||||||
|
{ XK_Return, XK_ANY_MOD, "\r", 0, 0},
|
||||||
|
{ XK_Insert, ShiftMask, "\033[4l", -1, 0},
|
||||||
|
{ XK_Insert, ShiftMask, "\033[2;2~", +1, 0},
|
||||||
|
{ XK_Insert, ControlMask, "\033[L", -1, 0},
|
||||||
|
{ XK_Insert, ControlMask, "\033[2;5~", +1, 0},
|
||||||
|
{ XK_Insert, XK_ANY_MOD, "\033[4h", -1, 0},
|
||||||
|
{ XK_Insert, XK_ANY_MOD, "\033[2~", +1, 0},
|
||||||
|
{ XK_Delete, ControlMask, "\033[M", -1, 0},
|
||||||
|
{ XK_Delete, ControlMask, "\033[3;5~", +1, 0},
|
||||||
|
{ XK_Delete, ShiftMask, "\033[2K", -1, 0},
|
||||||
|
{ XK_Delete, ShiftMask, "\033[3;2~", +1, 0},
|
||||||
|
{ XK_Delete, XK_ANY_MOD, "\033[P", -1, 0},
|
||||||
|
{ XK_Delete, XK_ANY_MOD, "\033[3~", +1, 0},
|
||||||
|
{ XK_BackSpace, XK_NO_MOD, "\177", 0, 0},
|
||||||
|
{ XK_BackSpace, Mod1Mask, "\033\177", 0, 0},
|
||||||
|
{ XK_Home, ShiftMask, "\033[2J", 0, -1},
|
||||||
|
{ XK_Home, ShiftMask, "\033[1;2H", 0, +1},
|
||||||
|
{ XK_Home, XK_ANY_MOD, "\033[H", 0, -1},
|
||||||
|
{ XK_Home, XK_ANY_MOD, "\033[1~", 0, +1},
|
||||||
|
{ XK_End, ControlMask, "\033[J", -1, 0},
|
||||||
|
{ XK_End, ControlMask, "\033[1;5F", +1, 0},
|
||||||
|
{ XK_End, ShiftMask, "\033[K", -1, 0},
|
||||||
|
{ XK_End, ShiftMask, "\033[1;2F", +1, 0},
|
||||||
|
{ XK_End, XK_ANY_MOD, "\033[4~", 0, 0},
|
||||||
|
{ XK_Prior, ControlMask, "\033[5;5~", 0, 0},
|
||||||
|
{ XK_Prior, ShiftMask, "\033[5;2~", 0, 0},
|
||||||
|
{ XK_Prior, XK_ANY_MOD, "\033[5~", 0, 0},
|
||||||
|
{ XK_Next, ControlMask, "\033[6;5~", 0, 0},
|
||||||
|
{ XK_Next, ShiftMask, "\033[6;2~", 0, 0},
|
||||||
|
{ XK_Next, XK_ANY_MOD, "\033[6~", 0, 0},
|
||||||
|
{ XK_F1, XK_NO_MOD, "\033OP" , 0, 0},
|
||||||
|
{ XK_F1, /* F13 */ ShiftMask, "\033[1;2P", 0, 0},
|
||||||
|
{ XK_F1, /* F25 */ ControlMask, "\033[1;5P", 0, 0},
|
||||||
|
{ XK_F1, /* F37 */ Mod4Mask, "\033[1;6P", 0, 0},
|
||||||
|
{ XK_F1, /* F49 */ Mod1Mask, "\033[1;3P", 0, 0},
|
||||||
|
{ XK_F1, /* F61 */ Mod3Mask, "\033[1;4P", 0, 0},
|
||||||
|
{ XK_F2, XK_NO_MOD, "\033OQ" , 0, 0},
|
||||||
|
{ XK_F2, /* F14 */ ShiftMask, "\033[1;2Q", 0, 0},
|
||||||
|
{ XK_F2, /* F26 */ ControlMask, "\033[1;5Q", 0, 0},
|
||||||
|
{ XK_F2, /* F38 */ Mod4Mask, "\033[1;6Q", 0, 0},
|
||||||
|
{ XK_F2, /* F50 */ Mod1Mask, "\033[1;3Q", 0, 0},
|
||||||
|
{ XK_F2, /* F62 */ Mod3Mask, "\033[1;4Q", 0, 0},
|
||||||
|
{ XK_F3, XK_NO_MOD, "\033OR" , 0, 0},
|
||||||
|
{ XK_F3, /* F15 */ ShiftMask, "\033[1;2R", 0, 0},
|
||||||
|
{ XK_F3, /* F27 */ ControlMask, "\033[1;5R", 0, 0},
|
||||||
|
{ XK_F3, /* F39 */ Mod4Mask, "\033[1;6R", 0, 0},
|
||||||
|
{ XK_F3, /* F51 */ Mod1Mask, "\033[1;3R", 0, 0},
|
||||||
|
{ XK_F3, /* F63 */ Mod3Mask, "\033[1;4R", 0, 0},
|
||||||
|
{ XK_F4, XK_NO_MOD, "\033OS" , 0, 0},
|
||||||
|
{ XK_F4, /* F16 */ ShiftMask, "\033[1;2S", 0, 0},
|
||||||
|
{ XK_F4, /* F28 */ ControlMask, "\033[1;5S", 0, 0},
|
||||||
|
{ XK_F4, /* F40 */ Mod4Mask, "\033[1;6S", 0, 0},
|
||||||
|
{ XK_F4, /* F52 */ Mod1Mask, "\033[1;3S", 0, 0},
|
||||||
|
{ XK_F5, XK_NO_MOD, "\033[15~", 0, 0},
|
||||||
|
{ XK_F5, /* F17 */ ShiftMask, "\033[15;2~", 0, 0},
|
||||||
|
{ XK_F5, /* F29 */ ControlMask, "\033[15;5~", 0, 0},
|
||||||
|
{ XK_F5, /* F41 */ Mod4Mask, "\033[15;6~", 0, 0},
|
||||||
|
{ XK_F5, /* F53 */ Mod1Mask, "\033[15;3~", 0, 0},
|
||||||
|
{ XK_F6, XK_NO_MOD, "\033[17~", 0, 0},
|
||||||
|
{ XK_F6, /* F18 */ ShiftMask, "\033[17;2~", 0, 0},
|
||||||
|
{ XK_F6, /* F30 */ ControlMask, "\033[17;5~", 0, 0},
|
||||||
|
{ XK_F6, /* F42 */ Mod4Mask, "\033[17;6~", 0, 0},
|
||||||
|
{ XK_F6, /* F54 */ Mod1Mask, "\033[17;3~", 0, 0},
|
||||||
|
{ XK_F7, XK_NO_MOD, "\033[18~", 0, 0},
|
||||||
|
{ XK_F7, /* F19 */ ShiftMask, "\033[18;2~", 0, 0},
|
||||||
|
{ XK_F7, /* F31 */ ControlMask, "\033[18;5~", 0, 0},
|
||||||
|
{ XK_F7, /* F43 */ Mod4Mask, "\033[18;6~", 0, 0},
|
||||||
|
{ XK_F7, /* F55 */ Mod1Mask, "\033[18;3~", 0, 0},
|
||||||
|
{ XK_F8, XK_NO_MOD, "\033[19~", 0, 0},
|
||||||
|
{ XK_F8, /* F20 */ ShiftMask, "\033[19;2~", 0, 0},
|
||||||
|
{ XK_F8, /* F32 */ ControlMask, "\033[19;5~", 0, 0},
|
||||||
|
{ XK_F8, /* F44 */ Mod4Mask, "\033[19;6~", 0, 0},
|
||||||
|
{ XK_F8, /* F56 */ Mod1Mask, "\033[19;3~", 0, 0},
|
||||||
|
{ XK_F9, XK_NO_MOD, "\033[20~", 0, 0},
|
||||||
|
{ XK_F9, /* F21 */ ShiftMask, "\033[20;2~", 0, 0},
|
||||||
|
{ XK_F9, /* F33 */ ControlMask, "\033[20;5~", 0, 0},
|
||||||
|
{ XK_F9, /* F45 */ Mod4Mask, "\033[20;6~", 0, 0},
|
||||||
|
{ XK_F9, /* F57 */ Mod1Mask, "\033[20;3~", 0, 0},
|
||||||
|
{ XK_F10, XK_NO_MOD, "\033[21~", 0, 0},
|
||||||
|
{ XK_F10, /* F22 */ ShiftMask, "\033[21;2~", 0, 0},
|
||||||
|
{ XK_F10, /* F34 */ ControlMask, "\033[21;5~", 0, 0},
|
||||||
|
{ XK_F10, /* F46 */ Mod4Mask, "\033[21;6~", 0, 0},
|
||||||
|
{ XK_F10, /* F58 */ Mod1Mask, "\033[21;3~", 0, 0},
|
||||||
|
{ XK_F11, XK_NO_MOD, "\033[23~", 0, 0},
|
||||||
|
{ XK_F11, /* F23 */ ShiftMask, "\033[23;2~", 0, 0},
|
||||||
|
{ XK_F11, /* F35 */ ControlMask, "\033[23;5~", 0, 0},
|
||||||
|
{ XK_F11, /* F47 */ Mod4Mask, "\033[23;6~", 0, 0},
|
||||||
|
{ XK_F11, /* F59 */ Mod1Mask, "\033[23;3~", 0, 0},
|
||||||
|
{ XK_F12, XK_NO_MOD, "\033[24~", 0, 0},
|
||||||
|
{ XK_F12, /* F24 */ ShiftMask, "\033[24;2~", 0, 0},
|
||||||
|
{ XK_F12, /* F36 */ ControlMask, "\033[24;5~", 0, 0},
|
||||||
|
{ XK_F12, /* F48 */ Mod4Mask, "\033[24;6~", 0, 0},
|
||||||
|
{ XK_F12, /* F60 */ Mod1Mask, "\033[24;3~", 0, 0},
|
||||||
|
{ XK_F13, XK_NO_MOD, "\033[1;2P", 0, 0},
|
||||||
|
{ XK_F14, XK_NO_MOD, "\033[1;2Q", 0, 0},
|
||||||
|
{ XK_F15, XK_NO_MOD, "\033[1;2R", 0, 0},
|
||||||
|
{ XK_F16, XK_NO_MOD, "\033[1;2S", 0, 0},
|
||||||
|
{ XK_F17, XK_NO_MOD, "\033[15;2~", 0, 0},
|
||||||
|
{ XK_F18, XK_NO_MOD, "\033[17;2~", 0, 0},
|
||||||
|
{ XK_F19, XK_NO_MOD, "\033[18;2~", 0, 0},
|
||||||
|
{ XK_F20, XK_NO_MOD, "\033[19;2~", 0, 0},
|
||||||
|
{ XK_F21, XK_NO_MOD, "\033[20;2~", 0, 0},
|
||||||
|
{ XK_F22, XK_NO_MOD, "\033[21;2~", 0, 0},
|
||||||
|
{ XK_F23, XK_NO_MOD, "\033[23;2~", 0, 0},
|
||||||
|
{ XK_F24, XK_NO_MOD, "\033[24;2~", 0, 0},
|
||||||
|
{ XK_F25, XK_NO_MOD, "\033[1;5P", 0, 0},
|
||||||
|
{ XK_F26, XK_NO_MOD, "\033[1;5Q", 0, 0},
|
||||||
|
{ XK_F27, XK_NO_MOD, "\033[1;5R", 0, 0},
|
||||||
|
{ XK_F28, XK_NO_MOD, "\033[1;5S", 0, 0},
|
||||||
|
{ XK_F29, XK_NO_MOD, "\033[15;5~", 0, 0},
|
||||||
|
{ XK_F30, XK_NO_MOD, "\033[17;5~", 0, 0},
|
||||||
|
{ XK_F31, XK_NO_MOD, "\033[18;5~", 0, 0},
|
||||||
|
{ XK_F32, XK_NO_MOD, "\033[19;5~", 0, 0},
|
||||||
|
{ XK_F33, XK_NO_MOD, "\033[20;5~", 0, 0},
|
||||||
|
{ XK_F34, XK_NO_MOD, "\033[21;5~", 0, 0},
|
||||||
|
{ XK_F35, XK_NO_MOD, "\033[23;5~", 0, 0},
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Selection types' masks.
|
||||||
|
* Use the same masks as usual.
|
||||||
|
* Button1Mask is always unset, to make masks match between ButtonPress.
|
||||||
|
* ButtonRelease and MotionNotify.
|
||||||
|
* If no match is found, regular selection is used.
|
||||||
|
*/
|
||||||
|
static uint selmasks[] = {
|
||||||
|
[SEL_RECTANGULAR] = Mod1Mask,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Printable characters in ASCII, used to estimate the advance width
|
||||||
|
* of single wide characters.
|
||||||
|
*/
|
||||||
|
static char ascii_printable[] =
|
||||||
|
" !\"#$%&'()*+,-./0123456789:;<=>?"
|
||||||
|
"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
|
||||||
|
"`abcdefghijklmnopqrstuvwxyz{|}~";
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
# st version
|
||||||
|
VERSION = 0.9.2
|
||||||
|
|
||||||
|
# Customize below to fit your system
|
||||||
|
|
||||||
|
# paths
|
||||||
|
PREFIX = /usr/local
|
||||||
|
MANPREFIX = $(PREFIX)/share/man
|
||||||
|
|
||||||
|
X11INC = /usr/X11R6/include
|
||||||
|
X11LIB = /usr/X11R6/lib
|
||||||
|
|
||||||
|
PKG_CONFIG = pkg-config
|
||||||
|
|
||||||
|
# includes and libs
|
||||||
|
INCS = -I$(X11INC) \
|
||||||
|
`$(PKG_CONFIG) --cflags fontconfig` \
|
||||||
|
`$(PKG_CONFIG) --cflags freetype2`
|
||||||
|
LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender \
|
||||||
|
`$(PKG_CONFIG) --libs fontconfig` \
|
||||||
|
`$(PKG_CONFIG) --libs freetype2`
|
||||||
|
|
||||||
|
# flags
|
||||||
|
STCPPFLAGS = -DVERSION=\"$(VERSION)\" -D_XOPEN_SOURCE=600
|
||||||
|
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 = c99
|
||||||
@@ -0,0 +1,146 @@
|
|||||||
|
diff --git a/config.def.h b/config.def.h
|
||||||
|
index 91ab8ca..6af616e 100644
|
||||||
|
--- a/config.def.h
|
||||||
|
+++ b/config.def.h
|
||||||
|
@@ -93,6 +93,9 @@ char *termname = "st-256color";
|
||||||
|
*/
|
||||||
|
unsigned int tabspaces = 8;
|
||||||
|
|
||||||
|
+/* bg opacity */
|
||||||
|
+float alpha = 0.8;
|
||||||
|
+
|
||||||
|
/* Terminal colors (16 first used in escape sequence) */
|
||||||
|
static const char *colorname[] = {
|
||||||
|
/* 8 normal colors */
|
||||||
|
diff --git a/config.mk b/config.mk
|
||||||
|
index 4c4c5d5..0114bad 100644
|
||||||
|
--- a/config.mk
|
||||||
|
+++ b/config.mk
|
||||||
|
@@ -16,7 +16,7 @@ PKG_CONFIG = pkg-config
|
||||||
|
INCS = -I$(X11INC) \
|
||||||
|
`$(PKG_CONFIG) --cflags fontconfig` \
|
||||||
|
`$(PKG_CONFIG) --cflags freetype2`
|
||||||
|
-LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft \
|
||||||
|
+LIBS = -L$(X11LIB) -lm -lrt -lX11 -lutil -lXft -lXrender\
|
||||||
|
`$(PKG_CONFIG) --libs fontconfig` \
|
||||||
|
`$(PKG_CONFIG) --libs freetype2`
|
||||||
|
|
||||||
|
diff --git a/st.h b/st.h
|
||||||
|
index 519b9bd..8bb533d 100644
|
||||||
|
--- a/st.h
|
||||||
|
+++ b/st.h
|
||||||
|
@@ -126,3 +126,4 @@ extern unsigned int tabspaces;
|
||||||
|
extern unsigned int defaultfg;
|
||||||
|
extern unsigned int defaultbg;
|
||||||
|
extern unsigned int defaultcs;
|
||||||
|
+extern float alpha;
|
||||||
|
diff --git a/x.c b/x.c
|
||||||
|
index 8a16faa..ddf4178 100644
|
||||||
|
--- a/x.c
|
||||||
|
+++ b/x.c
|
||||||
|
@@ -105,6 +105,7 @@ typedef struct {
|
||||||
|
XSetWindowAttributes attrs;
|
||||||
|
int scr;
|
||||||
|
int isfixed; /* is fixed geometry? */
|
||||||
|
+ int depth; /* bit depth */
|
||||||
|
int l, t; /* left and top offset */
|
||||||
|
int gm; /* geometry mask */
|
||||||
|
} XWindow;
|
||||||
|
@@ -243,6 +244,7 @@ static char *usedfont = NULL;
|
||||||
|
static double usedfontsize = 0;
|
||||||
|
static double defaultfontsize = 0;
|
||||||
|
|
||||||
|
+static char *opt_alpha = NULL;
|
||||||
|
static char *opt_class = NULL;
|
||||||
|
static char **opt_cmd = NULL;
|
||||||
|
static char *opt_embed = NULL;
|
||||||
|
@@ -736,7 +738,7 @@ xresize(int col, int row)
|
||||||
|
|
||||||
|
XFreePixmap(xw.dpy, xw.buf);
|
||||||
|
xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h,
|
||||||
|
- DefaultDepth(xw.dpy, xw.scr));
|
||||||
|
+ xw.depth);
|
||||||
|
XftDrawChange(xw.draw, xw.buf);
|
||||||
|
xclear(0, 0, win.w, win.h);
|
||||||
|
|
||||||
|
@@ -796,6 +798,13 @@ xloadcols(void)
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -1118,11 +1127,23 @@ xinit(int cols, int rows)
|
||||||
|
Window parent;
|
||||||
|
pid_t thispid = getpid();
|
||||||
|
XColor xmousefg, xmousebg;
|
||||||
|
+ XWindowAttributes attr;
|
||||||
|
+ XVisualInfo vis;
|
||||||
|
|
||||||
|
if (!(xw.dpy = XOpenDisplay(NULL)))
|
||||||
|
die("can't open display\n");
|
||||||
|
xw.scr = XDefaultScreen(xw.dpy);
|
||||||
|
- xw.vis = XDefaultVisual(xw.dpy, xw.scr);
|
||||||
|
+
|
||||||
|
+ 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;
|
||||||
|
|
||||||
|
/* font */
|
||||||
|
if (!FcInit())
|
||||||
|
@@ -1132,7 +1153,7 @@ xinit(int cols, int rows)
|
||||||
|
xloadfonts(usedfont, 0);
|
||||||
|
|
||||||
|
/* colors */
|
||||||
|
- xw.cmap = XDefaultColormap(xw.dpy, xw.scr);
|
||||||
|
+ xw.cmap = XCreateColormap(xw.dpy, parent, xw.vis, None);
|
||||||
|
xloadcols();
|
||||||
|
|
||||||
|
/* adjust fixed window geometry */
|
||||||
|
@@ -1152,19 +1173,15 @@ xinit(int cols, int rows)
|
||||||
|
| ButtonMotionMask | ButtonPressMask | ButtonReleaseMask;
|
||||||
|
xw.attrs.colormap = xw.cmap;
|
||||||
|
|
||||||
|
- if (!(opt_embed && (parent = strtol(opt_embed, NULL, 0))))
|
||||||
|
- parent = XRootWindow(xw.dpy, xw.scr);
|
||||||
|
xw.win = XCreateWindow(xw.dpy, parent, xw.l, xw.t,
|
||||||
|
- win.w, win.h, 0, XDefaultDepth(xw.dpy, xw.scr), InputOutput,
|
||||||
|
+ 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;
|
||||||
|
- dc.gc = XCreateGC(xw.dpy, parent, GCGraphicsExposures,
|
||||||
|
- &gcvalues);
|
||||||
|
- xw.buf = XCreatePixmap(xw.dpy, xw.win, win.w, win.h,
|
||||||
|
- DefaultDepth(xw.dpy, xw.scr));
|
||||||
|
+ 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);
|
||||||
|
|
||||||
|
@@ -2019,6 +2036,9 @@ main(int argc, char *argv[])
|
||||||
|
case 'a':
|
||||||
|
allowaltscreen = 0;
|
||||||
|
break;
|
||||||
|
+ case 'A':
|
||||||
|
+ opt_alpha = EARGF(usage());
|
||||||
|
+ break;
|
||||||
|
case 'c':
|
||||||
|
opt_class = EARGF(usage());
|
||||||
|
break;
|
||||||
@@ -0,0 +1,259 @@
|
|||||||
|
From 8c9c920325fa10440a96736ba58ec647a0365e22 Mon Sep 17 00:00:00 2001
|
||||||
|
From: "Avi Halachmi (:avih)" <avihpit@yahoo.com>
|
||||||
|
Date: Sat, 18 Apr 2020 13:56:11 +0300
|
||||||
|
Subject: [PATCH] application-sync: support Synchronized-Updates
|
||||||
|
|
||||||
|
See https://gitlab.com/gnachman/iterm2/-/wikis/synchronized-updates-spec
|
||||||
|
|
||||||
|
In a nutshell: allow an application to suspend drawing until it has
|
||||||
|
completed some output - so that the terminal will not flicker/tear by
|
||||||
|
rendering partial content. If the end-of-suspension sequence doesn't
|
||||||
|
arrive, the terminal bails out after a timeout (default: 200 ms).
|
||||||
|
|
||||||
|
The feature is supported and pioneered by iTerm2. There are probably
|
||||||
|
very few other terminals or applications which support this feature
|
||||||
|
currently.
|
||||||
|
|
||||||
|
One notable application which does support it is tmux (master as of
|
||||||
|
2020-04-18) - where cursor flicker is completely avoided when a pane
|
||||||
|
has new content. E.g. run in one pane: `while :; do cat x.c; done'
|
||||||
|
while the cursor is at another pane.
|
||||||
|
|
||||||
|
The terminfo string `Sync' added to `st.info' is also a tmux extension
|
||||||
|
which tmux detects automatically when `st.info` is installed.
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
|
||||||
|
- Draw-suspension begins on BSU sequence (Begin-Synchronized-Update),
|
||||||
|
and ends on ESU sequence (End-Synchronized-Update).
|
||||||
|
|
||||||
|
- BSU, ESU are "\033P=1s\033\\", "\033P=2s\033\\" respectively (DCS).
|
||||||
|
|
||||||
|
- SU doesn't support nesting - BSU begins or extends, ESU always ends.
|
||||||
|
|
||||||
|
- ESU without BSU is ignored.
|
||||||
|
|
||||||
|
- BSU after BSU extends (resets the timeout), so an application could
|
||||||
|
send BSU in a loop and keep drawing suspended - exactly like it can
|
||||||
|
not-draw anything in a loop. But as soon as it exits/aborted then
|
||||||
|
drawing is resumed according to the timeout even without ESU.
|
||||||
|
|
||||||
|
- This implementation focuses on ESU and doesn't really care about BSU
|
||||||
|
in the sense that it tries hard to draw exactly once ESU arrives (if
|
||||||
|
it's not too soon after the last draw - according to minlatency),
|
||||||
|
and doesn't try to draw the content just up-to BSU. These two sides
|
||||||
|
complement eachother - not-drawing on BSU increases the chance that
|
||||||
|
ESU is not too soon after the last draw. This approach was chosen
|
||||||
|
because the application's main focus is that ESU indicates to the
|
||||||
|
terminal that the content is now ready - and that's when we try to
|
||||||
|
draw.
|
||||||
|
---
|
||||||
|
config.def.h | 6 ++++++
|
||||||
|
st.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++--
|
||||||
|
st.info | 1 +
|
||||||
|
x.c | 22 +++++++++++++++++++---
|
||||||
|
4 files changed, 72 insertions(+), 5 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/config.def.h b/config.def.h
|
||||||
|
index 6f05dce..80d768e 100644
|
||||||
|
--- a/config.def.h
|
||||||
|
+++ b/config.def.h
|
||||||
|
@@ -56,6 +56,12 @@ int allowwindowops = 0;
|
||||||
|
static double minlatency = 8;
|
||||||
|
static double maxlatency = 33;
|
||||||
|
|
||||||
|
+/*
|
||||||
|
+ * Synchronized-Update timeout in ms
|
||||||
|
+ * https://gitlab.com/gnachman/iterm2/-/wikis/synchronized-updates-spec
|
||||||
|
+ */
|
||||||
|
+static uint su_timeout = 200;
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* blinking timeout (set to 0 to disable blinking) for the terminal blinking
|
||||||
|
* attribute.
|
||||||
|
diff --git a/st.c b/st.c
|
||||||
|
index 76b7e0d..0582e77 100644
|
||||||
|
--- a/st.c
|
||||||
|
+++ b/st.c
|
||||||
|
@@ -231,6 +231,33 @@ 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};
|
||||||
|
|
||||||
|
+#include <time.h>
|
||||||
|
+static int su = 0;
|
||||||
|
+struct timespec sutv;
|
||||||
|
+
|
||||||
|
+static void
|
||||||
|
+tsync_begin()
|
||||||
|
+{
|
||||||
|
+ clock_gettime(CLOCK_MONOTONIC, &sutv);
|
||||||
|
+ su = 1;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void
|
||||||
|
+tsync_end()
|
||||||
|
+{
|
||||||
|
+ su = 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+int
|
||||||
|
+tinsync(uint timeout)
|
||||||
|
+{
|
||||||
|
+ struct timespec now;
|
||||||
|
+ if (su && !clock_gettime(CLOCK_MONOTONIC, &now)
|
||||||
|
+ && TIMEDIFF(now, sutv) >= timeout)
|
||||||
|
+ su = 0;
|
||||||
|
+ return su;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
ssize_t
|
||||||
|
xwrite(int fd, const char *s, size_t len)
|
||||||
|
{
|
||||||
|
@@ -818,6 +845,9 @@ ttynew(char *line, char *cmd, char *out, char **args)
|
||||||
|
return cmdfd;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int twrite_aborted = 0;
|
||||||
|
+int ttyread_pending() { return twrite_aborted; }
|
||||||
|
+
|
||||||
|
size_t
|
||||||
|
ttyread(void)
|
||||||
|
{
|
||||||
|
@@ -826,7 +856,7 @@ ttyread(void)
|
||||||
|
int ret, written;
|
||||||
|
|
||||||
|
/* append read bytes to unprocessed bytes */
|
||||||
|
- ret = read(cmdfd, buf+buflen, LEN(buf)-buflen);
|
||||||
|
+ ret = twrite_aborted ? 1 : read(cmdfd, buf+buflen, LEN(buf)-buflen);
|
||||||
|
|
||||||
|
switch (ret) {
|
||||||
|
case 0:
|
||||||
|
@@ -834,7 +864,7 @@ ttyread(void)
|
||||||
|
case -1:
|
||||||
|
die("couldn't read from shell: %s\n", strerror(errno));
|
||||||
|
default:
|
||||||
|
- buflen += ret;
|
||||||
|
+ buflen += twrite_aborted ? 0 : ret;
|
||||||
|
written = twrite(buf, buflen, 0);
|
||||||
|
buflen -= written;
|
||||||
|
/* keep any incomplete UTF-8 byte sequence for the next call */
|
||||||
|
@@ -994,6 +1024,7 @@ tsetdirtattr(int attr)
|
||||||
|
void
|
||||||
|
tfulldirt(void)
|
||||||
|
{
|
||||||
|
+ tsync_end();
|
||||||
|
tsetdirt(0, term.row-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -1895,6 +1926,12 @@ strhandle(void)
|
||||||
|
xsettitle(strescseq.args[0]);
|
||||||
|
return;
|
||||||
|
case 'P': /* DCS -- Device Control String */
|
||||||
|
+ /* https://gitlab.com/gnachman/iterm2/-/wikis/synchronized-updates-spec */
|
||||||
|
+ if (strstr(strescseq.buf, "=1s") == strescseq.buf)
|
||||||
|
+ tsync_begin(); /* BSU */
|
||||||
|
+ else if (strstr(strescseq.buf, "=2s") == strescseq.buf)
|
||||||
|
+ tsync_end(); /* ESU */
|
||||||
|
+ return;
|
||||||
|
case '_': /* APC -- Application Program Command */
|
||||||
|
case '^': /* PM -- Privacy Message */
|
||||||
|
return;
|
||||||
|
@@ -2436,6 +2473,9 @@ twrite(const char *buf, int buflen, int show_ctrl)
|
||||||
|
Rune u;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
+ int su0 = su;
|
||||||
|
+ twrite_aborted = 0;
|
||||||
|
+
|
||||||
|
for (n = 0; n < buflen; n += charsize) {
|
||||||
|
if (IS_SET(MODE_UTF8)) {
|
||||||
|
/* process a complete utf8 char */
|
||||||
|
@@ -2446,6 +2486,10 @@ twrite(const char *buf, int buflen, int show_ctrl)
|
||||||
|
u = buf[n] & 0xFF;
|
||||||
|
charsize = 1;
|
||||||
|
}
|
||||||
|
+ if (su0 && !su) {
|
||||||
|
+ twrite_aborted = 1;
|
||||||
|
+ break; // ESU - allow rendering before a new BSU
|
||||||
|
+ }
|
||||||
|
if (show_ctrl && ISCONTROL(u)) {
|
||||||
|
if (u & 0x80) {
|
||||||
|
u &= 0x7f;
|
||||||
|
diff --git a/st.info b/st.info
|
||||||
|
index 8201ad6..b32b446 100644
|
||||||
|
--- a/st.info
|
||||||
|
+++ b/st.info
|
||||||
|
@@ -191,6 +191,7 @@ st-mono| simpleterm monocolor,
|
||||||
|
Ms=\E]52;%p1%s;%p2%s\007,
|
||||||
|
Se=\E[2 q,
|
||||||
|
Ss=\E[%p1%d q,
|
||||||
|
+ Sync=\EP=%p1%ds\E\\,
|
||||||
|
|
||||||
|
st| simpleterm,
|
||||||
|
use=st-mono,
|
||||||
|
diff --git a/x.c b/x.c
|
||||||
|
index 210f184..27ff4e2 100644
|
||||||
|
--- a/x.c
|
||||||
|
+++ b/x.c
|
||||||
|
@@ -1861,6 +1861,9 @@ resize(XEvent *e)
|
||||||
|
cresize(e->xconfigure.width, e->xconfigure.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
+int tinsync(uint);
|
||||||
|
+int ttyread_pending();
|
||||||
|
+
|
||||||
|
void
|
||||||
|
run(void)
|
||||||
|
{
|
||||||
|
@@ -1895,7 +1898,7 @@ run(void)
|
||||||
|
FD_SET(ttyfd, &rfd);
|
||||||
|
FD_SET(xfd, &rfd);
|
||||||
|
|
||||||
|
- if (XPending(xw.dpy))
|
||||||
|
+ if (XPending(xw.dpy) || ttyread_pending())
|
||||||
|
timeout = 0; /* existing events might not set xfd */
|
||||||
|
|
||||||
|
seltv.tv_sec = timeout / 1E3;
|
||||||
|
@@ -1909,7 +1912,8 @@ run(void)
|
||||||
|
}
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||||
|
|
||||||
|
- if (FD_ISSET(ttyfd, &rfd))
|
||||||
|
+ int ttyin = FD_ISSET(ttyfd, &rfd) || ttyread_pending();
|
||||||
|
+ if (ttyin)
|
||||||
|
ttyread();
|
||||||
|
|
||||||
|
xev = 0;
|
||||||
|
@@ -1933,7 +1937,7 @@ run(void)
|
||||||
|
* 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 (ttyin || xev) {
|
||||||
|
if (!drawing) {
|
||||||
|
trigger = now;
|
||||||
|
drawing = 1;
|
||||||
|
@@ -1944,6 +1948,18 @@ run(void)
|
||||||
|
continue; /* we have time, try to find idle */
|
||||||
|
}
|
||||||
|
|
||||||
|
+ if (tinsync(su_timeout)) {
|
||||||
|
+ /*
|
||||||
|
+ * on synchronized-update draw-suspension: don't reset
|
||||||
|
+ * drawing so that we draw ASAP once we can (just after
|
||||||
|
+ * ESU). it won't be too soon because we already can
|
||||||
|
+ * draw now but we skip. we set timeout > 0 to draw on
|
||||||
|
+ * SU-timeout even without new content.
|
||||||
|
+ */
|
||||||
|
+ timeout = minlatency;
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
/* idle detected or maxlatency exhausted -> draw */
|
||||||
|
timeout = -1;
|
||||||
|
if (blinktimeout && tattrset(ATTR_BLINK)) {
|
||||||
|
|
||||||
|
base-commit: b27a383a3acc7decf00e6e889fca265430b5d329
|
||||||
|
--
|
||||||
|
2.17.1
|
||||||
|
|
||||||
@@ -0,0 +1,600 @@
|
|||||||
|
From 3f3b80b9966c60086f4ed80ce4de0cbf03468d36 Mon Sep 17 00:00:00 2001
|
||||||
|
From: "Avi Halachmi (:avih)" <avihpit@yahoo.com>
|
||||||
|
Date: Wed, 26 Dec 2018 14:51:45 +0200
|
||||||
|
Subject: [PATCH] boxdraw_v2: custom render lines/blocks/braille for perfect
|
||||||
|
alignment
|
||||||
|
|
||||||
|
It seems impossible to ensure that blocks and line drawing glyphs
|
||||||
|
align without visible gaps for all combinations of arbitrary font,
|
||||||
|
size and width/height scale factor.
|
||||||
|
|
||||||
|
This commit adds options to render most of the lines/blocks and
|
||||||
|
braille codepoints without using the font such that they align
|
||||||
|
perfectly regardless of font, size or other configuration values.
|
||||||
|
|
||||||
|
Supported codepoints are U+2500 - U+259F except dashes/diagonals,
|
||||||
|
and U28XX.
|
||||||
|
|
||||||
|
The lines/blocks data is stored as 16-bit values at boxdraw_data.h
|
||||||
|
|
||||||
|
boxdraw/braille are independent, disabled by default at config[.def].h
|
||||||
|
---
|
||||||
|
Makefile | 3 +-
|
||||||
|
boxdraw.c | 194 ++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
boxdraw_data.h | 214 +++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
config.def.h | 12 +++
|
||||||
|
st.c | 3 +
|
||||||
|
st.h | 10 +++
|
||||||
|
x.c | 21 +++--
|
||||||
|
7 files changed, 451 insertions(+), 6 deletions(-)
|
||||||
|
create mode 100644 boxdraw.c
|
||||||
|
create mode 100644 boxdraw_data.h
|
||||||
|
|
||||||
|
diff --git a/Makefile b/Makefile
|
||||||
|
index 470ac86..6dfa212 100644
|
||||||
|
--- a/Makefile
|
||||||
|
+++ b/Makefile
|
||||||
|
@@ -4,7 +4,7 @@
|
||||||
|
|
||||||
|
include config.mk
|
||||||
|
|
||||||
|
-SRC = st.c x.c
|
||||||
|
+SRC = st.c x.c boxdraw.c
|
||||||
|
OBJ = $(SRC:.c=.o)
|
||||||
|
|
||||||
|
all: options st
|
||||||
|
@@ -23,6 +23,7 @@ config.h:
|
||||||
|
|
||||||
|
st.o: config.h st.h win.h
|
||||||
|
x.o: arg.h config.h st.h win.h
|
||||||
|
+boxdraw.o: config.h st.h boxdraw_data.h
|
||||||
|
|
||||||
|
$(OBJ): config.h config.mk
|
||||||
|
|
||||||
|
diff --git a/boxdraw.c b/boxdraw.c
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000..28a92d0
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/boxdraw.c
|
||||||
|
@@ -0,0 +1,194 @@
|
||||||
|
+/*
|
||||||
|
+ * Copyright 2018 Avi Halachmi (:avih) avihpit@yahoo.com https://github.com/avih
|
||||||
|
+ * MIT/X Consortium License
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#include <X11/Xft/Xft.h>
|
||||||
|
+#include "st.h"
|
||||||
|
+#include "boxdraw_data.h"
|
||||||
|
+
|
||||||
|
+/* Rounded non-negative integers division of n / d */
|
||||||
|
+#define DIV(n, d) (((n) + (d) / 2) / (d))
|
||||||
|
+
|
||||||
|
+static Display *xdpy;
|
||||||
|
+static Colormap xcmap;
|
||||||
|
+static XftDraw *xd;
|
||||||
|
+static Visual *xvis;
|
||||||
|
+
|
||||||
|
+static void drawbox(int, int, int, int, XftColor *, XftColor *, ushort);
|
||||||
|
+static void drawboxlines(int, int, int, int, XftColor *, ushort);
|
||||||
|
+
|
||||||
|
+/* public API */
|
||||||
|
+
|
||||||
|
+void
|
||||||
|
+boxdraw_xinit(Display *dpy, Colormap cmap, XftDraw *draw, Visual *vis)
|
||||||
|
+{
|
||||||
|
+ xdpy = dpy; xcmap = cmap; xd = draw, xvis = vis;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+int
|
||||||
|
+isboxdraw(Rune u)
|
||||||
|
+{
|
||||||
|
+ Rune block = u & ~0xff;
|
||||||
|
+ return (boxdraw && block == 0x2500 && boxdata[(uint8_t)u]) ||
|
||||||
|
+ (boxdraw_braille && block == 0x2800);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/* the "index" is actually the entire shape data encoded as ushort */
|
||||||
|
+ushort
|
||||||
|
+boxdrawindex(const Glyph *g)
|
||||||
|
+{
|
||||||
|
+ if (boxdraw_braille && (g->u & ~0xff) == 0x2800)
|
||||||
|
+ return BRL | (uint8_t)g->u;
|
||||||
|
+ if (boxdraw_bold && (g->mode & ATTR_BOLD))
|
||||||
|
+ return BDB | boxdata[(uint8_t)g->u];
|
||||||
|
+ return boxdata[(uint8_t)g->u];
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void
|
||||||
|
+drawboxes(int x, int y, int cw, int ch, XftColor *fg, XftColor *bg,
|
||||||
|
+ const XftGlyphFontSpec *specs, int len)
|
||||||
|
+{
|
||||||
|
+ for ( ; len-- > 0; x += cw, specs++)
|
||||||
|
+ drawbox(x, y, cw, ch, fg, bg, (ushort)specs->glyph);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/* implementation */
|
||||||
|
+
|
||||||
|
+void
|
||||||
|
+drawbox(int x, int y, int w, int h, XftColor *fg, XftColor *bg, ushort bd)
|
||||||
|
+{
|
||||||
|
+ ushort cat = bd & ~(BDB | 0xff); /* mask out bold and data */
|
||||||
|
+ if (bd & (BDL | BDA)) {
|
||||||
|
+ /* lines (light/double/heavy/arcs) */
|
||||||
|
+ drawboxlines(x, y, w, h, fg, bd);
|
||||||
|
+
|
||||||
|
+ } else if (cat == BBD) {
|
||||||
|
+ /* lower (8-X)/8 block */
|
||||||
|
+ int d = DIV((uint8_t)bd * h, 8);
|
||||||
|
+ XftDrawRect(xd, fg, x, y + d, w, h - d);
|
||||||
|
+
|
||||||
|
+ } else if (cat == BBU) {
|
||||||
|
+ /* upper X/8 block */
|
||||||
|
+ XftDrawRect(xd, fg, x, y, w, DIV((uint8_t)bd * h, 8));
|
||||||
|
+
|
||||||
|
+ } else if (cat == BBL) {
|
||||||
|
+ /* left X/8 block */
|
||||||
|
+ XftDrawRect(xd, fg, x, y, DIV((uint8_t)bd * w, 8), h);
|
||||||
|
+
|
||||||
|
+ } else if (cat == BBR) {
|
||||||
|
+ /* right (8-X)/8 block */
|
||||||
|
+ int d = DIV((uint8_t)bd * w, 8);
|
||||||
|
+ XftDrawRect(xd, fg, x + d, y, w - d, h);
|
||||||
|
+
|
||||||
|
+ } else if (cat == BBQ) {
|
||||||
|
+ /* Quadrants */
|
||||||
|
+ int w2 = DIV(w, 2), h2 = DIV(h, 2);
|
||||||
|
+ if (bd & TL)
|
||||||
|
+ XftDrawRect(xd, fg, x, y, w2, h2);
|
||||||
|
+ if (bd & TR)
|
||||||
|
+ XftDrawRect(xd, fg, x + w2, y, w - w2, h2);
|
||||||
|
+ if (bd & BL)
|
||||||
|
+ XftDrawRect(xd, fg, x, y + h2, w2, h - h2);
|
||||||
|
+ if (bd & BR)
|
||||||
|
+ XftDrawRect(xd, fg, x + w2, y + h2, w - w2, h - h2);
|
||||||
|
+
|
||||||
|
+ } else if (bd & BBS) {
|
||||||
|
+ /* Shades - data is 1/2/3 for 25%/50%/75% alpha, respectively */
|
||||||
|
+ int d = (uint8_t)bd;
|
||||||
|
+ XftColor xfc;
|
||||||
|
+ XRenderColor xrc = { .alpha = 0xffff };
|
||||||
|
+
|
||||||
|
+ xrc.red = DIV(fg->color.red * d + bg->color.red * (4 - d), 4);
|
||||||
|
+ xrc.green = DIV(fg->color.green * d + bg->color.green * (4 - d), 4);
|
||||||
|
+ xrc.blue = DIV(fg->color.blue * d + bg->color.blue * (4 - d), 4);
|
||||||
|
+
|
||||||
|
+ XftColorAllocValue(xdpy, xvis, xcmap, &xrc, &xfc);
|
||||||
|
+ XftDrawRect(xd, &xfc, x, y, w, h);
|
||||||
|
+ XftColorFree(xdpy, xvis, xcmap, &xfc);
|
||||||
|
+
|
||||||
|
+ } else if (cat == BRL) {
|
||||||
|
+ /* braille, each data bit corresponds to one dot at 2x4 grid */
|
||||||
|
+ int w1 = DIV(w, 2);
|
||||||
|
+ int h1 = DIV(h, 4), h2 = DIV(h, 2), h3 = DIV(3 * h, 4);
|
||||||
|
+
|
||||||
|
+ if (bd & 1) XftDrawRect(xd, fg, x, y, w1, h1);
|
||||||
|
+ if (bd & 2) XftDrawRect(xd, fg, x, y + h1, w1, h2 - h1);
|
||||||
|
+ if (bd & 4) XftDrawRect(xd, fg, x, y + h2, w1, h3 - h2);
|
||||||
|
+ if (bd & 8) XftDrawRect(xd, fg, x + w1, y, w - w1, h1);
|
||||||
|
+ if (bd & 16) XftDrawRect(xd, fg, x + w1, y + h1, w - w1, h2 - h1);
|
||||||
|
+ if (bd & 32) XftDrawRect(xd, fg, x + w1, y + h2, w - w1, h3 - h2);
|
||||||
|
+ if (bd & 64) XftDrawRect(xd, fg, x, y + h3, w1, h - h3);
|
||||||
|
+ if (bd & 128) XftDrawRect(xd, fg, x + w1, y + h3, w - w1, h - h3);
|
||||||
|
+
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void
|
||||||
|
+drawboxlines(int x, int y, int w, int h, XftColor *fg, ushort bd)
|
||||||
|
+{
|
||||||
|
+ /* s: stem thickness. width/8 roughly matches underscore thickness. */
|
||||||
|
+ /* We draw bold as 1.5 * normal-stem and at least 1px thicker. */
|
||||||
|
+ /* doubles draw at least 3px, even when w or h < 3. bold needs 6px. */
|
||||||
|
+ int mwh = MIN(w, h);
|
||||||
|
+ int base_s = MAX(1, DIV(mwh, 8));
|
||||||
|
+ int bold = (bd & BDB) && mwh >= 6; /* possibly ignore boldness */
|
||||||
|
+ int s = bold ? MAX(base_s + 1, DIV(3 * base_s, 2)) : base_s;
|
||||||
|
+ int w2 = DIV(w - s, 2), h2 = DIV(h - s, 2);
|
||||||
|
+ /* the s-by-s square (x + w2, y + h2, s, s) is the center texel. */
|
||||||
|
+ /* The base length (per direction till edge) includes this square. */
|
||||||
|
+
|
||||||
|
+ int light = bd & (LL | LU | LR | LD);
|
||||||
|
+ int double_ = bd & (DL | DU | DR | DD);
|
||||||
|
+
|
||||||
|
+ if (light) {
|
||||||
|
+ /* d: additional (negative) length to not-draw the center */
|
||||||
|
+ /* texel - at arcs and avoid drawing inside (some) doubles */
|
||||||
|
+ int arc = bd & BDA;
|
||||||
|
+ int multi_light = light & (light - 1);
|
||||||
|
+ int multi_double = double_ & (double_ - 1);
|
||||||
|
+ /* light crosses double only at DH+LV, DV+LH (ref. shapes) */
|
||||||
|
+ int d = arc || (multi_double && !multi_light) ? -s : 0;
|
||||||
|
+
|
||||||
|
+ if (bd & LL)
|
||||||
|
+ XftDrawRect(xd, fg, x, y + h2, w2 + s + d, s);
|
||||||
|
+ if (bd & LU)
|
||||||
|
+ XftDrawRect(xd, fg, x + w2, y, s, h2 + s + d);
|
||||||
|
+ if (bd & LR)
|
||||||
|
+ XftDrawRect(xd, fg, x + w2 - d, y + h2, w - w2 + d, s);
|
||||||
|
+ if (bd & LD)
|
||||||
|
+ XftDrawRect(xd, fg, x + w2, y + h2 - d, s, h - h2 + d);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* double lines - also align with light to form heavy when combined */
|
||||||
|
+ if (double_) {
|
||||||
|
+ /*
|
||||||
|
+ * going clockwise, for each double-ray: p is additional length
|
||||||
|
+ * to the single-ray nearer to the previous direction, and n to
|
||||||
|
+ * the next. p and n adjust from the base length to lengths
|
||||||
|
+ * which consider other doubles - shorter to avoid intersections
|
||||||
|
+ * (p, n), or longer to draw the far-corner texel (n).
|
||||||
|
+ */
|
||||||
|
+ int dl = bd & DL, du = bd & DU, dr = bd & DR, dd = bd & DD;
|
||||||
|
+ if (dl) {
|
||||||
|
+ int p = dd ? -s : 0, n = du ? -s : dd ? s : 0;
|
||||||
|
+ XftDrawRect(xd, fg, x, y + h2 + s, w2 + s + p, s);
|
||||||
|
+ XftDrawRect(xd, fg, x, y + h2 - s, w2 + s + n, s);
|
||||||
|
+ }
|
||||||
|
+ if (du) {
|
||||||
|
+ int p = dl ? -s : 0, n = dr ? -s : dl ? s : 0;
|
||||||
|
+ XftDrawRect(xd, fg, x + w2 - s, y, s, h2 + s + p);
|
||||||
|
+ XftDrawRect(xd, fg, x + w2 + s, y, s, h2 + s + n);
|
||||||
|
+ }
|
||||||
|
+ if (dr) {
|
||||||
|
+ int p = du ? -s : 0, n = dd ? -s : du ? s : 0;
|
||||||
|
+ XftDrawRect(xd, fg, x + w2 - p, y + h2 - s, w - w2 + p, s);
|
||||||
|
+ XftDrawRect(xd, fg, x + w2 - n, y + h2 + s, w - w2 + n, s);
|
||||||
|
+ }
|
||||||
|
+ if (dd) {
|
||||||
|
+ int p = dr ? -s : 0, n = dl ? -s : dr ? s : 0;
|
||||||
|
+ XftDrawRect(xd, fg, x + w2 + s, y + h2 - p, s, h - h2 + p);
|
||||||
|
+ XftDrawRect(xd, fg, x + w2 - s, y + h2 - n, s, h - h2 + n);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
diff --git a/boxdraw_data.h b/boxdraw_data.h
|
||||||
|
new file mode 100644
|
||||||
|
index 0000000..7890500
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/boxdraw_data.h
|
||||||
|
@@ -0,0 +1,214 @@
|
||||||
|
+/*
|
||||||
|
+ * Copyright 2018 Avi Halachmi (:avih) avihpit@yahoo.com https://github.com/avih
|
||||||
|
+ * MIT/X Consortium License
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * U+25XX codepoints data
|
||||||
|
+ *
|
||||||
|
+ * References:
|
||||||
|
+ * http://www.unicode.org/charts/PDF/U2500.pdf
|
||||||
|
+ * http://www.unicode.org/charts/PDF/U2580.pdf
|
||||||
|
+ *
|
||||||
|
+ * Test page:
|
||||||
|
+ * https://github.com/GNOME/vte/blob/master/doc/boxes.txt
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+/* Each shape is encoded as 16-bits. Higher bits are category, lower are data */
|
||||||
|
+/* Categories (mutually exclusive except BDB): */
|
||||||
|
+/* For convenience, BDL/BDA/BBS/BDB are 1 bit each, the rest are enums */
|
||||||
|
+#define BDL (1<<8) /* Box Draw Lines (light/double/heavy) */
|
||||||
|
+#define BDA (1<<9) /* Box Draw Arc (light) */
|
||||||
|
+
|
||||||
|
+#define BBD (1<<10) /* Box Block Down (lower) X/8 */
|
||||||
|
+#define BBL (2<<10) /* Box Block Left X/8 */
|
||||||
|
+#define BBU (3<<10) /* Box Block Upper X/8 */
|
||||||
|
+#define BBR (4<<10) /* Box Block Right X/8 */
|
||||||
|
+#define BBQ (5<<10) /* Box Block Quadrants */
|
||||||
|
+#define BRL (6<<10) /* Box Braille (data is lower byte of U28XX) */
|
||||||
|
+
|
||||||
|
+#define BBS (1<<14) /* Box Block Shades */
|
||||||
|
+#define BDB (1<<15) /* Box Draw is Bold */
|
||||||
|
+
|
||||||
|
+/* (BDL/BDA) Light/Double/Heavy x Left/Up/Right/Down/Horizontal/Vertical */
|
||||||
|
+/* Heavy is light+double (literally drawing light+double align to form heavy) */
|
||||||
|
+#define LL (1<<0)
|
||||||
|
+#define LU (1<<1)
|
||||||
|
+#define LR (1<<2)
|
||||||
|
+#define LD (1<<3)
|
||||||
|
+#define LH (LL+LR)
|
||||||
|
+#define LV (LU+LD)
|
||||||
|
+
|
||||||
|
+#define DL (1<<4)
|
||||||
|
+#define DU (1<<5)
|
||||||
|
+#define DR (1<<6)
|
||||||
|
+#define DD (1<<7)
|
||||||
|
+#define DH (DL+DR)
|
||||||
|
+#define DV (DU+DD)
|
||||||
|
+
|
||||||
|
+#define HL (LL+DL)
|
||||||
|
+#define HU (LU+DU)
|
||||||
|
+#define HR (LR+DR)
|
||||||
|
+#define HD (LD+DD)
|
||||||
|
+#define HH (HL+HR)
|
||||||
|
+#define HV (HU+HD)
|
||||||
|
+
|
||||||
|
+/* (BBQ) Quadrants Top/Bottom x Left/Right */
|
||||||
|
+#define TL (1<<0)
|
||||||
|
+#define TR (1<<1)
|
||||||
|
+#define BL (1<<2)
|
||||||
|
+#define BR (1<<3)
|
||||||
|
+
|
||||||
|
+/* Data for U+2500 - U+259F except dashes/diagonals */
|
||||||
|
+static const unsigned short boxdata[256] = {
|
||||||
|
+ /* light lines */
|
||||||
|
+ [0x00] = BDL + LH, /* light horizontal */
|
||||||
|
+ [0x02] = BDL + LV, /* light vertical */
|
||||||
|
+ [0x0c] = BDL + LD + LR, /* light down and right */
|
||||||
|
+ [0x10] = BDL + LD + LL, /* light down and left */
|
||||||
|
+ [0x14] = BDL + LU + LR, /* light up and right */
|
||||||
|
+ [0x18] = BDL + LU + LL, /* light up and left */
|
||||||
|
+ [0x1c] = BDL + LV + LR, /* light vertical and right */
|
||||||
|
+ [0x24] = BDL + LV + LL, /* light vertical and left */
|
||||||
|
+ [0x2c] = BDL + LH + LD, /* light horizontal and down */
|
||||||
|
+ [0x34] = BDL + LH + LU, /* light horizontal and up */
|
||||||
|
+ [0x3c] = BDL + LV + LH, /* light vertical and horizontal */
|
||||||
|
+ [0x74] = BDL + LL, /* light left */
|
||||||
|
+ [0x75] = BDL + LU, /* light up */
|
||||||
|
+ [0x76] = BDL + LR, /* light right */
|
||||||
|
+ [0x77] = BDL + LD, /* light down */
|
||||||
|
+
|
||||||
|
+ /* heavy [+light] lines */
|
||||||
|
+ [0x01] = BDL + HH,
|
||||||
|
+ [0x03] = BDL + HV,
|
||||||
|
+ [0x0d] = BDL + HR + LD,
|
||||||
|
+ [0x0e] = BDL + HD + LR,
|
||||||
|
+ [0x0f] = BDL + HD + HR,
|
||||||
|
+ [0x11] = BDL + HL + LD,
|
||||||
|
+ [0x12] = BDL + HD + LL,
|
||||||
|
+ [0x13] = BDL + HD + HL,
|
||||||
|
+ [0x15] = BDL + HR + LU,
|
||||||
|
+ [0x16] = BDL + HU + LR,
|
||||||
|
+ [0x17] = BDL + HU + HR,
|
||||||
|
+ [0x19] = BDL + HL + LU,
|
||||||
|
+ [0x1a] = BDL + HU + LL,
|
||||||
|
+ [0x1b] = BDL + HU + HL,
|
||||||
|
+ [0x1d] = BDL + HR + LV,
|
||||||
|
+ [0x1e] = BDL + HU + LD + LR,
|
||||||
|
+ [0x1f] = BDL + HD + LR + LU,
|
||||||
|
+ [0x20] = BDL + HV + LR,
|
||||||
|
+ [0x21] = BDL + HU + HR + LD,
|
||||||
|
+ [0x22] = BDL + HD + HR + LU,
|
||||||
|
+ [0x23] = BDL + HV + HR,
|
||||||
|
+ [0x25] = BDL + HL + LV,
|
||||||
|
+ [0x26] = BDL + HU + LD + LL,
|
||||||
|
+ [0x27] = BDL + HD + LU + LL,
|
||||||
|
+ [0x28] = BDL + HV + LL,
|
||||||
|
+ [0x29] = BDL + HU + HL + LD,
|
||||||
|
+ [0x2a] = BDL + HD + HL + LU,
|
||||||
|
+ [0x2b] = BDL + HV + HL,
|
||||||
|
+ [0x2d] = BDL + HL + LD + LR,
|
||||||
|
+ [0x2e] = BDL + HR + LL + LD,
|
||||||
|
+ [0x2f] = BDL + HH + LD,
|
||||||
|
+ [0x30] = BDL + HD + LH,
|
||||||
|
+ [0x31] = BDL + HD + HL + LR,
|
||||||
|
+ [0x32] = BDL + HR + HD + LL,
|
||||||
|
+ [0x33] = BDL + HH + HD,
|
||||||
|
+ [0x35] = BDL + HL + LU + LR,
|
||||||
|
+ [0x36] = BDL + HR + LU + LL,
|
||||||
|
+ [0x37] = BDL + HH + LU,
|
||||||
|
+ [0x38] = BDL + HU + LH,
|
||||||
|
+ [0x39] = BDL + HU + HL + LR,
|
||||||
|
+ [0x3a] = BDL + HU + HR + LL,
|
||||||
|
+ [0x3b] = BDL + HH + HU,
|
||||||
|
+ [0x3d] = BDL + HL + LV + LR,
|
||||||
|
+ [0x3e] = BDL + HR + LV + LL,
|
||||||
|
+ [0x3f] = BDL + HH + LV,
|
||||||
|
+ [0x40] = BDL + HU + LH + LD,
|
||||||
|
+ [0x41] = BDL + HD + LH + LU,
|
||||||
|
+ [0x42] = BDL + HV + LH,
|
||||||
|
+ [0x43] = BDL + HU + HL + LD + LR,
|
||||||
|
+ [0x44] = BDL + HU + HR + LD + LL,
|
||||||
|
+ [0x45] = BDL + HD + HL + LU + LR,
|
||||||
|
+ [0x46] = BDL + HD + HR + LU + LL,
|
||||||
|
+ [0x47] = BDL + HH + HU + LD,
|
||||||
|
+ [0x48] = BDL + HH + HD + LU,
|
||||||
|
+ [0x49] = BDL + HV + HL + LR,
|
||||||
|
+ [0x4a] = BDL + HV + HR + LL,
|
||||||
|
+ [0x4b] = BDL + HV + HH,
|
||||||
|
+ [0x78] = BDL + HL,
|
||||||
|
+ [0x79] = BDL + HU,
|
||||||
|
+ [0x7a] = BDL + HR,
|
||||||
|
+ [0x7b] = BDL + HD,
|
||||||
|
+ [0x7c] = BDL + HR + LL,
|
||||||
|
+ [0x7d] = BDL + HD + LU,
|
||||||
|
+ [0x7e] = BDL + HL + LR,
|
||||||
|
+ [0x7f] = BDL + HU + LD,
|
||||||
|
+
|
||||||
|
+ /* double [+light] lines */
|
||||||
|
+ [0x50] = BDL + DH,
|
||||||
|
+ [0x51] = BDL + DV,
|
||||||
|
+ [0x52] = BDL + DR + LD,
|
||||||
|
+ [0x53] = BDL + DD + LR,
|
||||||
|
+ [0x54] = BDL + DR + DD,
|
||||||
|
+ [0x55] = BDL + DL + LD,
|
||||||
|
+ [0x56] = BDL + DD + LL,
|
||||||
|
+ [0x57] = BDL + DL + DD,
|
||||||
|
+ [0x58] = BDL + DR + LU,
|
||||||
|
+ [0x59] = BDL + DU + LR,
|
||||||
|
+ [0x5a] = BDL + DU + DR,
|
||||||
|
+ [0x5b] = BDL + DL + LU,
|
||||||
|
+ [0x5c] = BDL + DU + LL,
|
||||||
|
+ [0x5d] = BDL + DL + DU,
|
||||||
|
+ [0x5e] = BDL + DR + LV,
|
||||||
|
+ [0x5f] = BDL + DV + LR,
|
||||||
|
+ [0x60] = BDL + DV + DR,
|
||||||
|
+ [0x61] = BDL + DL + LV,
|
||||||
|
+ [0x62] = BDL + DV + LL,
|
||||||
|
+ [0x63] = BDL + DV + DL,
|
||||||
|
+ [0x64] = BDL + DH + LD,
|
||||||
|
+ [0x65] = BDL + DD + LH,
|
||||||
|
+ [0x66] = BDL + DD + DH,
|
||||||
|
+ [0x67] = BDL + DH + LU,
|
||||||
|
+ [0x68] = BDL + DU + LH,
|
||||||
|
+ [0x69] = BDL + DH + DU,
|
||||||
|
+ [0x6a] = BDL + DH + LV,
|
||||||
|
+ [0x6b] = BDL + DV + LH,
|
||||||
|
+ [0x6c] = BDL + DH + DV,
|
||||||
|
+
|
||||||
|
+ /* (light) arcs */
|
||||||
|
+ [0x6d] = BDA + LD + LR,
|
||||||
|
+ [0x6e] = BDA + LD + LL,
|
||||||
|
+ [0x6f] = BDA + LU + LL,
|
||||||
|
+ [0x70] = BDA + LU + LR,
|
||||||
|
+
|
||||||
|
+ /* Lower (Down) X/8 block (data is 8 - X) */
|
||||||
|
+ [0x81] = BBD + 7, [0x82] = BBD + 6, [0x83] = BBD + 5, [0x84] = BBD + 4,
|
||||||
|
+ [0x85] = BBD + 3, [0x86] = BBD + 2, [0x87] = BBD + 1, [0x88] = BBD + 0,
|
||||||
|
+
|
||||||
|
+ /* Left X/8 block (data is X) */
|
||||||
|
+ [0x89] = BBL + 7, [0x8a] = BBL + 6, [0x8b] = BBL + 5, [0x8c] = BBL + 4,
|
||||||
|
+ [0x8d] = BBL + 3, [0x8e] = BBL + 2, [0x8f] = BBL + 1,
|
||||||
|
+
|
||||||
|
+ /* upper 1/2 (4/8), 1/8 block (X), right 1/2, 1/8 block (8-X) */
|
||||||
|
+ [0x80] = BBU + 4, [0x94] = BBU + 1,
|
||||||
|
+ [0x90] = BBR + 4, [0x95] = BBR + 7,
|
||||||
|
+
|
||||||
|
+ /* Quadrants */
|
||||||
|
+ [0x96] = BBQ + BL,
|
||||||
|
+ [0x97] = BBQ + BR,
|
||||||
|
+ [0x98] = BBQ + TL,
|
||||||
|
+ [0x99] = BBQ + TL + BL + BR,
|
||||||
|
+ [0x9a] = BBQ + TL + BR,
|
||||||
|
+ [0x9b] = BBQ + TL + TR + BL,
|
||||||
|
+ [0x9c] = BBQ + TL + TR + BR,
|
||||||
|
+ [0x9d] = BBQ + TR,
|
||||||
|
+ [0x9e] = BBQ + BL + TR,
|
||||||
|
+ [0x9f] = BBQ + BL + TR + BR,
|
||||||
|
+
|
||||||
|
+ /* Shades, data is an alpha value in 25% units (1/4, 1/2, 3/4) */
|
||||||
|
+ [0x91] = BBS + 1, [0x92] = BBS + 2, [0x93] = BBS + 3,
|
||||||
|
+
|
||||||
|
+ /* U+2504 - U+250B, U+254C - U+254F: unsupported (dashes) */
|
||||||
|
+ /* U+2571 - U+2573: unsupported (diagonals) */
|
||||||
|
+};
|
||||||
|
diff --git a/config.def.h b/config.def.h
|
||||||
|
index 0895a1f..bf6718b 100644
|
||||||
|
--- a/config.def.h
|
||||||
|
+++ b/config.def.h
|
||||||
|
@@ -58,6 +58,18 @@ static unsigned int blinktimeout = 800;
|
||||||
|
*/
|
||||||
|
static unsigned int cursorthickness = 2;
|
||||||
|
|
||||||
|
+/*
|
||||||
|
+ * 1: render most of the lines/blocks characters without using the font for
|
||||||
|
+ * perfect alignment between cells (U2500 - U259F except dashes/diagonals).
|
||||||
|
+ * Bold affects lines thickness if boxdraw_bold is not 0. Italic is ignored.
|
||||||
|
+ * 0: disable (render all U25XX glyphs normally from the font).
|
||||||
|
+ */
|
||||||
|
+const int boxdraw = 0;
|
||||||
|
+const int boxdraw_bold = 0;
|
||||||
|
+
|
||||||
|
+/* braille (U28XX): 1: render as adjacent "pixels", 0: use font */
|
||||||
|
+const int boxdraw_braille = 0;
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* bell volume. It must be a value between -100 and 100. Use 0 for disabling
|
||||||
|
* it
|
||||||
|
diff --git a/st.c b/st.c
|
||||||
|
index 0ce6ac2..c035e19 100644
|
||||||
|
--- a/st.c
|
||||||
|
+++ b/st.c
|
||||||
|
@@ -1230,6 +1230,9 @@ tsetchar(Rune u, Glyph *attr, int x, int y)
|
||||||
|
term.dirty[y] = 1;
|
||||||
|
term.line[y][x] = *attr;
|
||||||
|
term.line[y][x].u = u;
|
||||||
|
+
|
||||||
|
+ if (isboxdraw(u))
|
||||||
|
+ term.line[y][x].mode |= ATTR_BOXDRAW;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
diff --git a/st.h b/st.h
|
||||||
|
index d978458..a6c382a 100644
|
||||||
|
--- a/st.h
|
||||||
|
+++ b/st.h
|
||||||
|
@@ -33,6 +33,7 @@ enum glyph_attribute {
|
||||||
|
ATTR_WRAP = 1 << 8,
|
||||||
|
ATTR_WIDE = 1 << 9,
|
||||||
|
ATTR_WDUMMY = 1 << 10,
|
||||||
|
+ ATTR_BOXDRAW = 1 << 11,
|
||||||
|
ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,
|
||||||
|
};
|
||||||
|
|
||||||
|
@@ -111,6 +112,14 @@ void *xmalloc(size_t);
|
||||||
|
void *xrealloc(void *, size_t);
|
||||||
|
char *xstrdup(char *);
|
||||||
|
|
||||||
|
+int isboxdraw(Rune);
|
||||||
|
+ushort boxdrawindex(const Glyph *);
|
||||||
|
+#ifdef XFT_VERSION
|
||||||
|
+/* only exposed to x.c, otherwise we'll need Xft.h for the types */
|
||||||
|
+void boxdraw_xinit(Display *, Colormap, XftDraw *, Visual *);
|
||||||
|
+void drawboxes(int, int, int, int, XftColor *, XftColor *, const XftGlyphFontSpec *, int);
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
/* config.h globals */
|
||||||
|
extern char *utmp;
|
||||||
|
extern char *scroll;
|
||||||
|
@@ -122,3 +131,4 @@ extern char *termname;
|
||||||
|
extern unsigned int tabspaces;
|
||||||
|
extern unsigned int defaultfg;
|
||||||
|
extern unsigned int defaultbg;
|
||||||
|
+extern const int boxdraw, boxdraw_bold, boxdraw_braille;
|
||||||
|
diff --git a/x.c b/x.c
|
||||||
|
index e5f1737..6f7ea2c 100644
|
||||||
|
--- a/x.c
|
||||||
|
+++ b/x.c
|
||||||
|
@@ -1205,6 +1205,8 @@ xinit(int cols, int rows)
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
@@ -1251,8 +1253,13 @@ xmakeglyphfontspecs(XftGlyphFontSpec *specs, const Glyph *glyphs, int len, int x
|
||||||
|
yp = winy + font->ascent;
|
||||||
|
}
|
||||||
|
|
||||||
|
- /* Lookup character index with default font. */
|
||||||
|
- glyphidx = XftCharIndex(xw.dpy, font->match, rune);
|
||||||
|
+ 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;
|
||||||
|
@@ -1456,8 +1463,12 @@ xdrawglyphfontspecs(const XftGlyphFontSpec *specs, Glyph base, int len, int x, i
|
||||||
|
r.width = width;
|
||||||
|
XftDrawSetClipRectangles(xw.draw, winx, winy, &r, 1);
|
||||||
|
|
||||||
|
- /* 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) {
|
||||||
|
@@ -1500,7 +1511,7 @@ xdrawcursor(int cx, int cy, Glyph g, int ox, int oy, Glyph og)
|
||||||
|
/*
|
||||||
|
* Select the right color for the right mode.
|
||||||
|
*/
|
||||||
|
- g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE;
|
||||||
|
+ g.mode &= ATTR_BOLD|ATTR_ITALIC|ATTR_UNDERLINE|ATTR_STRUCK|ATTR_WIDE|ATTR_BOXDRAW;
|
||||||
|
|
||||||
|
if (IS_SET(MODE_REVERSE)) {
|
||||||
|
g.mode |= ATTR_REVERSE;
|
||||||
|
|
||||||
|
base-commit: 43a395ae91f7d67ce694e65edeaa7bbc720dd027
|
||||||
|
--
|
||||||
|
2.20.1
|
||||||
|
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
diff -up ../st-0.8.4/config.def.h ./config.def.h
|
||||||
|
--- ../st-0.8.4/config.def.h 2020-06-19 10:29:45.000000000 +0100
|
||||||
|
+++ ./config.def.h 2021-01-29 22:40:56.451916768 +0000
|
||||||
|
@@ -199,6 +199,7 @@ static Shortcut shortcuts[] = {
|
||||||
|
{ TERMMOD, XK_Y, selpaste, {.i = 0} },
|
||||||
|
{ ShiftMask, XK_Insert, selpaste, {.i = 0} },
|
||||||
|
{ TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
|
||||||
|
+ { MODKEY, XK_l, copyurl, {.i = 0} },
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
diff -up ../st-0.8.4/st.c ./st.c
|
||||||
|
--- ../st-0.8.4/st.c 2020-06-19 10:29:45.000000000 +0100
|
||||||
|
+++ ./st.c 2021-01-29 22:41:18.031954197 +0000
|
||||||
|
@@ -200,6 +200,8 @@ static void tdefutf8(char);
|
||||||
|
static int32_t tdefcolor(int *, int *, int);
|
||||||
|
static void tdeftran(char);
|
||||||
|
static void tstrsequence(uchar);
|
||||||
|
+static void tsetcolor(int, int, int, uint32_t, uint32_t);
|
||||||
|
+static char * findlastany(char *, const char**, size_t);
|
||||||
|
|
||||||
|
static void drawregion(int, int, int, int);
|
||||||
|
|
||||||
|
@@ -2595,3 +2597,122 @@ redraw(void)
|
||||||
|
tfulldirt();
|
||||||
|
draw();
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+void
|
||||||
|
+tsetcolor( int row, int start, int end, uint32_t fg, uint32_t bg )
|
||||||
|
+{
|
||||||
|
+ int i = start;
|
||||||
|
+ for( ; i < end; ++i )
|
||||||
|
+ {
|
||||||
|
+ term.line[row][i].fg = fg;
|
||||||
|
+ term.line[row][i].bg = bg;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+char *
|
||||||
|
+findlastany(char *str, const char** find, size_t len)
|
||||||
|
+{
|
||||||
|
+ char* found = NULL;
|
||||||
|
+ int i = 0;
|
||||||
|
+ for(found = str + strlen(str) - 1; found >= str; --found) {
|
||||||
|
+ for(i = 0; i < len; i++) {
|
||||||
|
+ if(strncmp(found, find[i], strlen(find[i])) == 0) {
|
||||||
|
+ return found;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return NULL;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+** Select and copy the previous url on screen (do nothing if there's no url).
|
||||||
|
+**
|
||||||
|
+** FIXME: doesn't handle urls that span multiple lines; will need to add support
|
||||||
|
+** for multiline "getsel()" first
|
||||||
|
+*/
|
||||||
|
+void
|
||||||
|
+copyurl(const Arg *arg) {
|
||||||
|
+ /* () and [] can appear in urls, but excluding them here will reduce false
|
||||||
|
+ * positives when figuring out where a given url ends.
|
||||||
|
+ */
|
||||||
|
+ static char URLCHARS[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
+ "abcdefghijklmnopqrstuvwxyz"
|
||||||
|
+ "0123456789-._~:/?#@!$&'*+,;=%";
|
||||||
|
+
|
||||||
|
+ static const char* URLSTRINGS[] = {"http://", "https://"};
|
||||||
|
+
|
||||||
|
+ /* remove highlighting from previous selection if any */
|
||||||
|
+ if(sel.ob.x >= 0 && sel.oe.x >= 0)
|
||||||
|
+ tsetcolor(sel.nb.y, sel.ob.x, sel.oe.x + 1, defaultfg, defaultbg);
|
||||||
|
+
|
||||||
|
+ int i = 0,
|
||||||
|
+ row = 0, /* row of current URL */
|
||||||
|
+ col = 0, /* column of current URL start */
|
||||||
|
+ startrow = 0, /* row of last occurrence */
|
||||||
|
+ colend = 0, /* column of last occurrence */
|
||||||
|
+ passes = 0; /* how many rows have been scanned */
|
||||||
|
+
|
||||||
|
+ char *linestr = calloc(term.col+1, sizeof(Rune));
|
||||||
|
+ char *c = NULL,
|
||||||
|
+ *match = NULL;
|
||||||
|
+
|
||||||
|
+ row = (sel.ob.x >= 0 && sel.nb.y > 0) ? sel.nb.y : term.bot;
|
||||||
|
+ LIMIT(row, term.top, term.bot);
|
||||||
|
+ startrow = row;
|
||||||
|
+
|
||||||
|
+ colend = (sel.ob.x >= 0 && sel.nb.y > 0) ? sel.nb.x : term.col;
|
||||||
|
+ LIMIT(colend, 0, term.col);
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ ** Scan from (term.bot,term.col) to (0,0) and find
|
||||||
|
+ ** next occurrance of a URL
|
||||||
|
+ */
|
||||||
|
+ while(passes !=term.bot + 2) {
|
||||||
|
+ /* Read in each column of every row until
|
||||||
|
+ ** we hit previous occurrence of URL
|
||||||
|
+ */
|
||||||
|
+ for (col = 0, i = 0; col < colend; ++col,++i) {
|
||||||
|
+ linestr[i] = term.line[row][col].u;
|
||||||
|
+ }
|
||||||
|
+ linestr[term.col] = '\0';
|
||||||
|
+
|
||||||
|
+ if ((match = findlastany(linestr, URLSTRINGS,
|
||||||
|
+ sizeof(URLSTRINGS)/sizeof(URLSTRINGS[0]))))
|
||||||
|
+ break;
|
||||||
|
+
|
||||||
|
+ if (--row < term.top)
|
||||||
|
+ row = term.bot;
|
||||||
|
+
|
||||||
|
+ colend = term.col;
|
||||||
|
+ passes++;
|
||||||
|
+ };
|
||||||
|
+
|
||||||
|
+ if (match) {
|
||||||
|
+ /* must happen before trim */
|
||||||
|
+ selclear();
|
||||||
|
+ sel.ob.x = strlen(linestr) - strlen(match);
|
||||||
|
+
|
||||||
|
+ /* trim the rest of the line from the url match */
|
||||||
|
+ for (c = match; *c != '\0'; ++c)
|
||||||
|
+ if (!strchr(URLCHARS, *c)) {
|
||||||
|
+ *c = '\0';
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* highlight selection by inverting terminal colors */
|
||||||
|
+ tsetcolor(row, sel.ob.x, sel.ob.x + strlen( match ), defaultbg, defaultfg);
|
||||||
|
+
|
||||||
|
+ /* select and copy */
|
||||||
|
+ sel.mode = 1;
|
||||||
|
+ sel.type = SEL_REGULAR;
|
||||||
|
+ sel.oe.x = sel.ob.x + strlen(match)-1;
|
||||||
|
+ sel.ob.y = sel.oe.y = row;
|
||||||
|
+ selnormalize();
|
||||||
|
+ tsetdirt(sel.nb.y, sel.ne.y);
|
||||||
|
+ xsetsel(getsel());
|
||||||
|
+ xclipcopy();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ free(linestr);
|
||||||
|
+}
|
||||||
|
Only in .: st-copyurl-0.8.4.diff
|
||||||
|
Only in .: st-copyurl-20190202-3be4cf1.diff
|
||||||
|
diff -up ../st-0.8.4/st.h ./st.h
|
||||||
|
--- ../st-0.8.4/st.h 2020-06-19 10:29:45.000000000 +0100
|
||||||
|
+++ ./st.h 2021-01-29 22:40:56.451916768 +0000
|
||||||
|
@@ -85,6 +85,7 @@ void printscreen(const Arg *);
|
||||||
|
void printsel(const Arg *);
|
||||||
|
void sendbreak(const Arg *);
|
||||||
|
void toggleprinter(const Arg *);
|
||||||
|
+void copyurl(const Arg *);
|
||||||
|
|
||||||
|
int tattrset(int);
|
||||||
|
void tnew(int, int);
|
||||||
@@ -0,0 +1,167 @@
|
|||||||
|
From ba724004c6a368e452114f7dc147a9978fe0f3b4 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Kirill Bugaev <kirill.bugaev87@gmail.com>
|
||||||
|
Date: Tue, 16 Apr 2019 04:31:30 +0800
|
||||||
|
Subject: [PATCH] This patch allows to add spare font besides default. Some
|
||||||
|
glyphs can be not present in default font. For this glyphs st uses
|
||||||
|
font-config and try to find them in font cache first. This patch append fonts
|
||||||
|
defined in font2 variable to the beginning of font cache. So they will be
|
||||||
|
used first for glyphs that absent in default font.
|
||||||
|
|
||||||
|
---
|
||||||
|
config.def.h | 6 +++
|
||||||
|
x.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
2 files changed, 107 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/config.def.h b/config.def.h
|
||||||
|
index 482901e..676719e 100644
|
||||||
|
--- a/config.def.h
|
||||||
|
+++ b/config.def.h
|
||||||
|
@@ -6,6 +6,12 @@
|
||||||
|
* font: see http://freedesktop.org/software/fontconfig/fontconfig-user.html
|
||||||
|
*/
|
||||||
|
static char *font = "Liberation Mono:pixelsize=12:antialias=true:autohint=true";
|
||||||
|
+/* Spare fonts */
|
||||||
|
+static char *font2[] = {
|
||||||
|
+/* "Inconsolata for Powerline:pixelsize=12:antialias=true:autohint=true", */
|
||||||
|
+/* "Hack Nerd Font Mono:pixelsize=11:antialias=true:autohint=true", */
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
static int borderpx = 2;
|
||||||
|
|
||||||
|
/*
|
||||||
|
diff --git a/x.c b/x.c
|
||||||
|
index 5828a3b..d37e59d 100644
|
||||||
|
--- a/x.c
|
||||||
|
+++ b/x.c
|
||||||
|
@@ -149,6 +149,8 @@ static void xhints(void);
|
||||||
|
static int xloadcolor(int, const char *, Color *);
|
||||||
|
static int xloadfont(Font *, FcPattern *);
|
||||||
|
static void xloadfonts(char *, double);
|
||||||
|
+static int xloadsparefont(FcPattern *, int);
|
||||||
|
+static void xloadsparefonts(void);
|
||||||
|
static void xunloadfont(Font *);
|
||||||
|
static void xunloadfonts(void);
|
||||||
|
static void xsetenv(void);
|
||||||
|
@@ -296,6 +298,7 @@ zoomabs(const Arg *arg)
|
||||||
|
{
|
||||||
|
xunloadfonts();
|
||||||
|
xloadfonts(usedfont, arg->f);
|
||||||
|
+ xloadsparefonts();
|
||||||
|
cresize(0, 0);
|
||||||
|
redraw();
|
||||||
|
xhints();
|
||||||
|
@@ -977,6 +980,101 @@ xloadfonts(char *fontstr, double fontsize)
|
||||||
|
FcPatternDestroy(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
+int
|
||||||
|
+xloadsparefont(FcPattern *pattern, int flags)
|
||||||
|
+{
|
||||||
|
+ FcPattern *match;
|
||||||
|
+ FcResult result;
|
||||||
|
+
|
||||||
|
+ match = FcFontMatch(NULL, pattern, &result);
|
||||||
|
+ if (!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++;
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+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");
|
||||||
|
+
|
||||||
|
+ /* 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));
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ 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)
|
||||||
|
{
|
||||||
|
@@ -1057,6 +1155,9 @@ xinit(int cols, int rows)
|
||||||
|
usedfont = (opt_font == NULL)? font : opt_font;
|
||||||
|
xloadfonts(usedfont, 0);
|
||||||
|
|
||||||
|
+ /* spare fonts */
|
||||||
|
+ xloadsparefonts();
|
||||||
|
+
|
||||||
|
/* colors */
|
||||||
|
xw.cmap = XDefaultColormap(xw.dpy, xw.scr);
|
||||||
|
xloadcols();
|
||||||
|
--
|
||||||
|
2.21.0
|
||||||
|
|
||||||
@@ -0,0 +1,319 @@
|
|||||||
|
diff --git a/config.def.h b/config.def.h
|
||||||
|
index 6f05dce..54612d1 100644
|
||||||
|
--- a/config.def.h
|
||||||
|
+++ b/config.def.h
|
||||||
|
@@ -199,6 +199,7 @@ static Shortcut shortcuts[] = {
|
||||||
|
{ TERMMOD, XK_Y, selpaste, {.i = 0} },
|
||||||
|
{ ShiftMask, XK_Insert, selpaste, {.i = 0} },
|
||||||
|
{ TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
|
||||||
|
+ { TERMMOD, XK_Escape, keyboard_select,{.i = 0} },
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
diff --git a/st.c b/st.c
|
||||||
|
index ef8abd5..0c6c6ca 100644
|
||||||
|
--- a/st.c
|
||||||
|
+++ b/st.c
|
||||||
|
@@ -16,6 +16,8 @@
|
||||||
|
#include <termios.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
+#include <X11/keysym.h>
|
||||||
|
+#include <X11/X.h>
|
||||||
|
|
||||||
|
#include "st.h"
|
||||||
|
#include "win.h"
|
||||||
|
@@ -2487,6 +2489,9 @@ tresize(int col, int row)
|
||||||
|
int *bp;
|
||||||
|
TCursor c;
|
||||||
|
|
||||||
|
+ if ( row < term.row || col < term.col )
|
||||||
|
+ toggle_winmode(trt_kbdselect(XK_Escape, NULL, 0));
|
||||||
|
+
|
||||||
|
if (col < 1 || row < 1) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"tresize: error resizing to %dx%d\n", col, row);
|
||||||
|
@@ -2612,3 +2617,220 @@ redraw(void)
|
||||||
|
tfulldirt();
|
||||||
|
draw();
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+void set_notifmode(int type, KeySym ksym) {
|
||||||
|
+ static char *lib[] = { " MOVE ", " SEL "};
|
||||||
|
+ static Glyph *g, *deb, *fin;
|
||||||
|
+ static int col, bot;
|
||||||
|
+
|
||||||
|
+ if ( ksym == -1 ) {
|
||||||
|
+ free(g);
|
||||||
|
+ col = term.col, bot = term.bot;
|
||||||
|
+ g = xmalloc(col * sizeof(Glyph));
|
||||||
|
+ memcpy(g, term.line[bot], col * sizeof(Glyph));
|
||||||
|
+
|
||||||
|
+ }
|
||||||
|
+ else if ( ksym == -2 )
|
||||||
|
+ memcpy(term.line[bot], g, col * sizeof(Glyph));
|
||||||
|
+
|
||||||
|
+ if ( type < 2 ) {
|
||||||
|
+ char *z = lib[type];
|
||||||
|
+ for (deb = &term.line[bot][col - 6], fin = &term.line[bot][col]; deb < fin; z++, deb++)
|
||||||
|
+ deb->mode = ATTR_REVERSE,
|
||||||
|
+ deb->u = *z,
|
||||||
|
+ deb->fg = defaultfg, deb->bg = defaultbg;
|
||||||
|
+ }
|
||||||
|
+ else if ( type < 5 )
|
||||||
|
+ memcpy(term.line[bot], g, col * sizeof(Glyph));
|
||||||
|
+ else {
|
||||||
|
+ for (deb = &term.line[bot][0], fin = &term.line[bot][col]; deb < fin; deb++)
|
||||||
|
+ deb->mode = ATTR_REVERSE,
|
||||||
|
+ deb->u = ' ',
|
||||||
|
+ deb->fg = defaultfg, deb->bg = defaultbg;
|
||||||
|
+ term.line[bot][0].u = ksym;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ term.dirty[bot] = 1;
|
||||||
|
+ drawregion(0, bot, col, bot + 1);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void select_or_drawcursor(int selectsearch_mode, int type) {
|
||||||
|
+ int done = 0;
|
||||||
|
+
|
||||||
|
+ if ( selectsearch_mode & 1 ) {
|
||||||
|
+ selextend(term.c.x, term.c.y, type, done);
|
||||||
|
+ xsetsel(getsel());
|
||||||
|
+ }
|
||||||
|
+ else
|
||||||
|
+ xdrawcursor(term.c.x, term.c.y, term.line[term.c.y][term.c.x],
|
||||||
|
+ term.ocx, term.ocy, term.line[term.ocy][term.ocx]);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void search(int selectsearch_mode, Rune *target, int ptarget, int incr, int type, TCursor *cu) {
|
||||||
|
+ Rune *r;
|
||||||
|
+ int i, bound = (term.col * cu->y + cu->x) * (incr > 0) + incr;
|
||||||
|
+
|
||||||
|
+ for (i = term.col * term.c.y + term.c.x + incr; i != bound; i += incr) {
|
||||||
|
+ for (r = target; r - target < ptarget; r++) {
|
||||||
|
+ if ( *r == term.line[(i + r - target) / term.col][(i + r - target) % term.col].u ) {
|
||||||
|
+ if ( r - target == ptarget - 1 ) break;
|
||||||
|
+ } else {
|
||||||
|
+ r = NULL;
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ if ( r != NULL ) break;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if ( i != bound ) {
|
||||||
|
+ term.c.y = i / term.col, term.c.x = i % term.col;
|
||||||
|
+ select_or_drawcursor(selectsearch_mode, type);
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+int trt_kbdselect(KeySym ksym, char *buf, int len) {
|
||||||
|
+ static TCursor cu;
|
||||||
|
+ static Rune target[64];
|
||||||
|
+ static int type = 1, ptarget, in_use;
|
||||||
|
+ static int sens, quant;
|
||||||
|
+ static char selectsearch_mode;
|
||||||
|
+ int i, bound, *xy;
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+ if ( selectsearch_mode & 2 ) {
|
||||||
|
+ if ( ksym == XK_Return ) {
|
||||||
|
+ selectsearch_mode ^= 2;
|
||||||
|
+ set_notifmode(selectsearch_mode, -2);
|
||||||
|
+ if ( ksym == XK_Escape ) ptarget = 0;
|
||||||
|
+ return 0;
|
||||||
|
+ }
|
||||||
|
+ else if ( ksym == XK_BackSpace ) {
|
||||||
|
+ if ( !ptarget ) return 0;
|
||||||
|
+ term.line[term.bot][ptarget--].u = ' ';
|
||||||
|
+ }
|
||||||
|
+ else if ( len < 1 ) {
|
||||||
|
+ return 0;
|
||||||
|
+ }
|
||||||
|
+ else if ( ptarget == term.col || ksym == XK_Escape ) {
|
||||||
|
+ return 0;
|
||||||
|
+ }
|
||||||
|
+ else {
|
||||||
|
+ utf8decode(buf, &target[ptarget++], len);
|
||||||
|
+ term.line[term.bot][ptarget].u = target[ptarget - 1];
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if ( ksym != XK_BackSpace )
|
||||||
|
+ search(selectsearch_mode, &target[0], ptarget, sens, type, &cu);
|
||||||
|
+
|
||||||
|
+ term.dirty[term.bot] = 1;
|
||||||
|
+ drawregion(0, term.bot, term.col, term.bot + 1);
|
||||||
|
+ return 0;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ switch ( ksym ) {
|
||||||
|
+ case -1 :
|
||||||
|
+ in_use = 1;
|
||||||
|
+ cu.x = term.c.x, cu.y = term.c.y;
|
||||||
|
+ set_notifmode(0, ksym);
|
||||||
|
+ return MODE_KBDSELECT;
|
||||||
|
+ case XK_s :
|
||||||
|
+ if ( selectsearch_mode & 1 )
|
||||||
|
+ selclear();
|
||||||
|
+ else
|
||||||
|
+ selstart(term.c.x, term.c.y, 0);
|
||||||
|
+ set_notifmode(selectsearch_mode ^= 1, ksym);
|
||||||
|
+ break;
|
||||||
|
+ case XK_t :
|
||||||
|
+ selextend(term.c.x, term.c.y, type ^= 3, i = 0); /* 2 fois */
|
||||||
|
+ selextend(term.c.x, term.c.y, type, i = 0);
|
||||||
|
+ break;
|
||||||
|
+ case XK_slash :
|
||||||
|
+ case XK_KP_Divide :
|
||||||
|
+ case XK_question :
|
||||||
|
+ ksym &= XK_question; /* Divide to slash */
|
||||||
|
+ sens = (ksym == XK_slash) ? -1 : 1;
|
||||||
|
+ ptarget = 0;
|
||||||
|
+ set_notifmode(15, ksym);
|
||||||
|
+ selectsearch_mode ^= 2;
|
||||||
|
+ break;
|
||||||
|
+ case XK_Escape :
|
||||||
|
+ if ( !in_use ) break;
|
||||||
|
+ selclear();
|
||||||
|
+ case XK_Return :
|
||||||
|
+ set_notifmode(4, ksym);
|
||||||
|
+ term.c.x = cu.x, term.c.y = cu.y;
|
||||||
|
+ select_or_drawcursor(selectsearch_mode = 0, type);
|
||||||
|
+ in_use = quant = 0;
|
||||||
|
+ return MODE_KBDSELECT;
|
||||||
|
+ case XK_n :
|
||||||
|
+ case XK_N :
|
||||||
|
+ if ( ptarget )
|
||||||
|
+ search(selectsearch_mode, &target[0], ptarget, (ksym == XK_n) ? -1 : 1, type, &cu);
|
||||||
|
+ break;
|
||||||
|
+ case XK_BackSpace :
|
||||||
|
+ term.c.x = 0;
|
||||||
|
+ select_or_drawcursor(selectsearch_mode, type);
|
||||||
|
+ break;
|
||||||
|
+ case XK_dollar :
|
||||||
|
+ term.c.x = term.col - 1;
|
||||||
|
+ select_or_drawcursor(selectsearch_mode, type);
|
||||||
|
+ break;
|
||||||
|
+ case XK_Home :
|
||||||
|
+ term.c.x = 0, term.c.y = 0;
|
||||||
|
+ select_or_drawcursor(selectsearch_mode, type);
|
||||||
|
+ break;
|
||||||
|
+ case XK_End :
|
||||||
|
+ term.c.x = cu.x, term.c.y = cu.y;
|
||||||
|
+ select_or_drawcursor(selectsearch_mode, type);
|
||||||
|
+ break;
|
||||||
|
+ case XK_Page_Up :
|
||||||
|
+ case XK_Page_Down :
|
||||||
|
+ term.c.y = (ksym == XK_Prior ) ? 0 : cu.y;
|
||||||
|
+ select_or_drawcursor(selectsearch_mode, type);
|
||||||
|
+ break;
|
||||||
|
+ case XK_exclam :
|
||||||
|
+ term.c.x = term.col >> 1;
|
||||||
|
+ select_or_drawcursor(selectsearch_mode, type);
|
||||||
|
+ break;
|
||||||
|
+ case XK_asterisk :
|
||||||
|
+ case XK_KP_Multiply :
|
||||||
|
+ term.c.x = term.col >> 1;
|
||||||
|
+ case XK_underscore :
|
||||||
|
+ term.c.y = cu.y >> 1;
|
||||||
|
+ select_or_drawcursor(selectsearch_mode, type);
|
||||||
|
+ break;
|
||||||
|
+ default :
|
||||||
|
+ if ( ksym >= XK_0 && ksym <= XK_9 ) { /* 0-9 keyboard */
|
||||||
|
+ quant = (quant * 10) + (ksym ^ XK_0);
|
||||||
|
+ return 0;
|
||||||
|
+ }
|
||||||
|
+ else if ( ksym >= XK_KP_0 && ksym <= XK_KP_9 ) { /* 0-9 numpad */
|
||||||
|
+ quant = (quant * 10) + (ksym ^ XK_KP_0);
|
||||||
|
+ return 0;
|
||||||
|
+ }
|
||||||
|
+ else if ( ksym == XK_k || ksym == XK_h )
|
||||||
|
+ i = ksym & 1;
|
||||||
|
+ else if ( ksym == XK_l || ksym == XK_j )
|
||||||
|
+ i = ((ksym & 6) | 4) >> 1;
|
||||||
|
+ else if ( (XK_Home & ksym) != XK_Home || (i = (ksym ^ XK_Home) - 1) > 3 )
|
||||||
|
+ break;
|
||||||
|
+
|
||||||
|
+ xy = (i & 1) ? &term.c.y : &term.c.x;
|
||||||
|
+ sens = (i & 2) ? 1 : -1;
|
||||||
|
+ bound = (i >> 1 ^ 1) ? 0 : (i ^ 3) ? term.col - 1 : term.bot;
|
||||||
|
+
|
||||||
|
+ if ( quant == 0 )
|
||||||
|
+ quant++;
|
||||||
|
+
|
||||||
|
+ if ( *xy == bound && ((sens < 0 && bound == 0) || (sens > 0 && bound > 0)) )
|
||||||
|
+ break;
|
||||||
|
+
|
||||||
|
+ *xy += quant * sens;
|
||||||
|
+ if ( *xy < 0 || ( bound > 0 && *xy > bound) )
|
||||||
|
+ *xy = bound;
|
||||||
|
+
|
||||||
|
+ select_or_drawcursor(selectsearch_mode, type);
|
||||||
|
+ }
|
||||||
|
+ quant = 0;
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
diff --git a/st.h b/st.h
|
||||||
|
index 3d351b6..2d1a11b 100644
|
||||||
|
--- a/st.h
|
||||||
|
+++ b/st.h
|
||||||
|
@@ -110,6 +110,7 @@ size_t utf8encode(Rune, char *);
|
||||||
|
void *xmalloc(size_t);
|
||||||
|
void *xrealloc(void *, size_t);
|
||||||
|
char *xstrdup(char *);
|
||||||
|
+int trt_kbdselect(KeySym, char *, int);
|
||||||
|
|
||||||
|
/* config.h globals */
|
||||||
|
extern char *utmp;
|
||||||
|
diff --git a/win.h b/win.h
|
||||||
|
index a6ef1b9..9a47fbb 100644
|
||||||
|
--- a/win.h
|
||||||
|
+++ b/win.h
|
||||||
|
@@ -21,6 +21,7 @@ enum win_mode {
|
||||||
|
MODE_NUMLOCK = 1 << 17,
|
||||||
|
MODE_MOUSE = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\
|
||||||
|
|MODE_MOUSEMANY,
|
||||||
|
+ MODE_KBDSELECT = 1 << 18,
|
||||||
|
};
|
||||||
|
|
||||||
|
void xbell(void);
|
||||||
|
@@ -36,4 +37,6 @@ void xsetmode(int, unsigned int);
|
||||||
|
void xsetpointermotion(int);
|
||||||
|
void xsetsel(char *);
|
||||||
|
int xstartdraw(void);
|
||||||
|
+void toggle_winmode(int);
|
||||||
|
+void keyboard_select(const Arg *);
|
||||||
|
void xximspot(int, int);
|
||||||
|
diff --git a/x.c b/x.c
|
||||||
|
index 210f184..b77ce54 100644
|
||||||
|
--- a/x.c
|
||||||
|
+++ b/x.c
|
||||||
|
@@ -1800,6 +1800,12 @@ kpress(XEvent *ev)
|
||||||
|
len = XmbLookupString(xw.ime.xic, e, buf, sizeof buf, &ksym, &status);
|
||||||
|
else
|
||||||
|
len = XLookupString(e, buf, sizeof buf, &ksym, NULL);
|
||||||
|
+ if ( IS_SET(MODE_KBDSELECT) ) {
|
||||||
|
+ if ( match(XK_NO_MOD, e->state) ||
|
||||||
|
+ (XK_Shift_L | XK_Shift_R) & e->state )
|
||||||
|
+ win.mode ^= trt_kbdselect(ksym, buf, len);
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
/* 1. shortcuts */
|
||||||
|
for (bp = shortcuts; bp < shortcuts + LEN(shortcuts); bp++) {
|
||||||
|
if (ksym == bp->keysym && match(bp->mod, e->state)) {
|
||||||
|
@@ -1977,6 +1983,14 @@ usage(void)
|
||||||
|
" [stty_args ...]\n", argv0, argv0);
|
||||||
|
}
|
||||||
|
|
||||||
|
+void toggle_winmode(int flag) {
|
||||||
|
+ win.mode ^= flag;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void keyboard_select(const Arg *dummy) {
|
||||||
|
+ win.mode ^= trt_kbdselect(-1, NULL, 0);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
int
|
||||||
|
main(int argc, char *argv[])
|
||||||
|
{
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
From 8a3e3d9f0de95c55321761e2763cf43666da312d Mon Sep 17 00:00:00 2001
|
||||||
|
From: Michael Buch <michaelbuch12@gmail.com>
|
||||||
|
Date: Sat, 2 Feb 2019 14:52:56 +0000
|
||||||
|
Subject: [PATCH] Add ability to open clipboard with configured program
|
||||||
|
|
||||||
|
---
|
||||||
|
config.def.h | 1 +
|
||||||
|
st.h | 1 +
|
||||||
|
x.c | 19 +++++++++++++++++++
|
||||||
|
3 files changed, 21 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/config.def.h b/config.def.h
|
||||||
|
index 0e01717..c273252 100644
|
||||||
|
--- a/config.def.h
|
||||||
|
+++ b/config.def.h
|
||||||
|
@@ -178,6 +178,7 @@ static Shortcut shortcuts[] = {
|
||||||
|
{ TERMMOD, XK_Y, selpaste, {.i = 0} },
|
||||||
|
{ ShiftMask, XK_Insert, selpaste, {.i = 0} },
|
||||||
|
{ TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
|
||||||
|
+ { MODKEY, XK_o, opencopied, {.v = "xdg-open"} },
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
diff --git a/st.h b/st.h
|
||||||
|
index 38c61c4..a0d7a83 100644
|
||||||
|
--- a/st.h
|
||||||
|
+++ b/st.h
|
||||||
|
@@ -80,6 +80,7 @@ void die(const char *, ...);
|
||||||
|
void redraw(void);
|
||||||
|
void draw(void);
|
||||||
|
|
||||||
|
+void opencopied(const Arg *);
|
||||||
|
void printscreen(const Arg *);
|
||||||
|
void printsel(const Arg *);
|
||||||
|
void sendbreak(const Arg *);
|
||||||
|
diff --git a/x.c b/x.c
|
||||||
|
index 0422421..af75e85 100644
|
||||||
|
--- a/x.c
|
||||||
|
+++ b/x.c
|
||||||
|
@@ -1953,3 +1953,22 @@ run:
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+void
|
||||||
|
+opencopied(const Arg *arg)
|
||||||
|
+{
|
||||||
|
+ size_t const max_cmd = 2048;
|
||||||
|
+ char * const clip = xsel.clipboard;
|
||||||
|
+ if(!clip) {
|
||||||
|
+ fprintf(stderr, "Warning: nothing copied to clipboard\n");
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* account for space/quote (3) and \0 (1) and & (1) */
|
||||||
|
+ /* e.g.: xdg-open "https://st.suckless.org"& */
|
||||||
|
+ size_t const cmd_size = max_cmd + strlen(clip) + 5;
|
||||||
|
+ char cmd[cmd_size];
|
||||||
|
+
|
||||||
|
+ snprintf(cmd, cmd_size, "%s \"%s\"&", (char *)arg->v, clip);
|
||||||
|
+ system(cmd);
|
||||||
|
+}
|
||||||
|
--
|
||||||
|
2.20.1
|
||||||
|
|
||||||
@@ -0,0 +1,351 @@
|
|||||||
|
diff --git a/config.def.h b/config.def.h
|
||||||
|
index 6f05dce..93cbcc0 100644
|
||||||
|
--- a/config.def.h
|
||||||
|
+++ b/config.def.h
|
||||||
|
@@ -199,6 +199,8 @@ static Shortcut shortcuts[] = {
|
||||||
|
{ TERMMOD, XK_Y, selpaste, {.i = 0} },
|
||||||
|
{ ShiftMask, XK_Insert, selpaste, {.i = 0} },
|
||||||
|
{ TERMMOD, XK_Num_Lock, numlock, {.i = 0} },
|
||||||
|
+ { ShiftMask, XK_Page_Up, kscrollup, {.i = -1} },
|
||||||
|
+ { ShiftMask, XK_Page_Down, kscrolldown, {.i = -1} },
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
diff --git a/st.c b/st.c
|
||||||
|
index ebdf360..817cc47 100644
|
||||||
|
--- a/st.c
|
||||||
|
+++ b/st.c
|
||||||
|
@@ -35,6 +35,7 @@
|
||||||
|
#define ESC_ARG_SIZ 16
|
||||||
|
#define STR_BUF_SIZ ESC_BUF_SIZ
|
||||||
|
#define STR_ARG_SIZ ESC_ARG_SIZ
|
||||||
|
+#define HISTSIZE 2000
|
||||||
|
|
||||||
|
/* macros */
|
||||||
|
#define IS_SET(flag) ((term.mode & (flag)) != 0)
|
||||||
|
@@ -42,6 +43,9 @@
|
||||||
|
#define ISCONTROLC1(c) (BETWEEN(c, 0x80, 0x9f))
|
||||||
|
#define ISCONTROL(c) (ISCONTROLC0(c) || ISCONTROLC1(c))
|
||||||
|
#define ISDELIM(u) (u && wcschr(worddelimiters, u))
|
||||||
|
+#define TLINE(y) ((y) < term.scr ? term.hist[((y) + term.histi - \
|
||||||
|
+ term.scr + HISTSIZE + 1) % HISTSIZE] : \
|
||||||
|
+ term.line[(y) - term.scr])
|
||||||
|
|
||||||
|
enum term_mode {
|
||||||
|
MODE_WRAP = 1 << 0,
|
||||||
|
@@ -115,6 +119,9 @@ typedef struct {
|
||||||
|
int col; /* nb col */
|
||||||
|
Line *line; /* screen */
|
||||||
|
Line *alt; /* alternate screen */
|
||||||
|
+ Line hist[HISTSIZE]; /* history buffer */
|
||||||
|
+ int histi; /* history index */
|
||||||
|
+ int scr; /* scroll back */
|
||||||
|
int *dirty; /* dirtyness of lines */
|
||||||
|
TCursor c; /* cursor */
|
||||||
|
int ocx; /* old cursor col */
|
||||||
|
@@ -184,8 +191,8 @@ static void tnewline(int);
|
||||||
|
static void tputtab(int);
|
||||||
|
static void tputc(Rune);
|
||||||
|
static void treset(void);
|
||||||
|
-static void tscrollup(int, int);
|
||||||
|
-static void tscrolldown(int, int);
|
||||||
|
+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 tsetdirt(int, int);
|
||||||
|
@@ -416,10 +423,10 @@ tlinelen(int y)
|
||||||
|
{
|
||||||
|
int i = term.col;
|
||||||
|
|
||||||
|
- if (term.line[y][i - 1].mode & ATTR_WRAP)
|
||||||
|
+ if (TLINE(y)[i - 1].mode & ATTR_WRAP)
|
||||||
|
return i;
|
||||||
|
|
||||||
|
- while (i > 0 && term.line[y][i - 1].u == ' ')
|
||||||
|
+ while (i > 0 && TLINE(y)[i - 1].u == ' ')
|
||||||
|
--i;
|
||||||
|
|
||||||
|
return i;
|
||||||
|
@@ -528,7 +535,7 @@ selsnap(int *x, int *y, int direction)
|
||||||
|
* Snap around if the word wraps around at the end or
|
||||||
|
* beginning of a line.
|
||||||
|
*/
|
||||||
|
- prevgp = &term.line[*y][*x];
|
||||||
|
+ prevgp = &TLINE(*y)[*x];
|
||||||
|
prevdelim = ISDELIM(prevgp->u);
|
||||||
|
for (;;) {
|
||||||
|
newx = *x + direction;
|
||||||
|
@@ -543,14 +550,14 @@ selsnap(int *x, int *y, int direction)
|
||||||
|
yt = *y, xt = *x;
|
||||||
|
else
|
||||||
|
yt = newy, xt = newx;
|
||||||
|
- if (!(term.line[yt][xt].mode & ATTR_WRAP))
|
||||||
|
+ if (!(TLINE(yt)[xt].mode & ATTR_WRAP))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newx >= tlinelen(newy))
|
||||||
|
break;
|
||||||
|
|
||||||
|
- gp = &term.line[newy][newx];
|
||||||
|
+ gp = &TLINE(newy)[newx];
|
||||||
|
delim = ISDELIM(gp->u);
|
||||||
|
if (!(gp->mode & ATTR_WDUMMY) && (delim != prevdelim
|
||||||
|
|| (delim && gp->u != prevgp->u)))
|
||||||
|
@@ -571,14 +578,14 @@ selsnap(int *x, int *y, int direction)
|
||||||
|
*x = (direction < 0) ? 0 : term.col - 1;
|
||||||
|
if (direction < 0) {
|
||||||
|
for (; *y > 0; *y += direction) {
|
||||||
|
- if (!(term.line[*y-1][term.col-1].mode
|
||||||
|
+ if (!(TLINE(*y-1)[term.col-1].mode
|
||||||
|
& ATTR_WRAP)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (direction > 0) {
|
||||||
|
for (; *y < term.row-1; *y += direction) {
|
||||||
|
- if (!(term.line[*y][term.col-1].mode
|
||||||
|
+ if (!(TLINE(*y)[term.col-1].mode
|
||||||
|
& ATTR_WRAP)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
@@ -609,13 +616,13 @@ getsel(void)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sel.type == SEL_RECTANGULAR) {
|
||||||
|
- gp = &term.line[y][sel.nb.x];
|
||||||
|
+ gp = &TLINE(y)[sel.nb.x];
|
||||||
|
lastx = sel.ne.x;
|
||||||
|
} else {
|
||||||
|
- gp = &term.line[y][sel.nb.y == y ? sel.nb.x : 0];
|
||||||
|
+ gp = &TLINE(y)[sel.nb.y == y ? sel.nb.x : 0];
|
||||||
|
lastx = (sel.ne.y == y) ? sel.ne.x : term.col-1;
|
||||||
|
}
|
||||||
|
- last = &term.line[y][MIN(lastx, linelen-1)];
|
||||||
|
+ last = &TLINE(y)[MIN(lastx, linelen-1)];
|
||||||
|
while (last >= gp && last->u == ' ')
|
||||||
|
--last;
|
||||||
|
|
||||||
|
@@ -850,6 +857,9 @@ void
|
||||||
|
ttywrite(const char *s, size_t n, int may_echo)
|
||||||
|
{
|
||||||
|
const char *next;
|
||||||
|
+ Arg arg = (Arg) { .i = term.scr };
|
||||||
|
+
|
||||||
|
+ kscrolldown(&arg);
|
||||||
|
|
||||||
|
if (may_echo && IS_SET(MODE_ECHO))
|
||||||
|
twrite(s, n, 1);
|
||||||
|
@@ -1061,13 +1071,53 @@ tswapscreen(void)
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
-tscrolldown(int orig, int n)
|
||||||
|
+kscrolldown(const Arg* a)
|
||||||
|
+{
|
||||||
|
+ int n = a->i;
|
||||||
|
+
|
||||||
|
+ if (n < 0)
|
||||||
|
+ n = term.row + n;
|
||||||
|
+
|
||||||
|
+ if (n > term.scr)
|
||||||
|
+ n = term.scr;
|
||||||
|
+
|
||||||
|
+ if (term.scr > 0) {
|
||||||
|
+ term.scr -= n;
|
||||||
|
+ selscroll(0, -n);
|
||||||
|
+ tfulldirt();
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void
|
||||||
|
+kscrollup(const Arg* a)
|
||||||
|
+{
|
||||||
|
+ int n = a->i;
|
||||||
|
+
|
||||||
|
+ if (n < 0)
|
||||||
|
+ n = term.row + n;
|
||||||
|
+
|
||||||
|
+ if (term.scr <= HISTSIZE-n) {
|
||||||
|
+ term.scr += n;
|
||||||
|
+ selscroll(0, n);
|
||||||
|
+ tfulldirt();
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void
|
||||||
|
+tscrolldown(int orig, int n, int copyhist)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
Line temp;
|
||||||
|
|
||||||
|
LIMIT(n, 0, term.bot-orig+1);
|
||||||
|
|
||||||
|
+ if (copyhist) {
|
||||||
|
+ term.histi = (term.histi - 1 + HISTSIZE) % HISTSIZE;
|
||||||
|
+ temp = term.hist[term.histi];
|
||||||
|
+ term.hist[term.histi] = term.line[term.bot];
|
||||||
|
+ term.line[term.bot] = temp;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
tsetdirt(orig, term.bot-n);
|
||||||
|
tclearregion(0, term.bot-n+1, term.col-1, term.bot);
|
||||||
|
|
||||||
|
@@ -1077,17 +1127,28 @@ tscrolldown(int orig, int n)
|
||||||
|
term.line[i-n] = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
- selscroll(orig, n);
|
||||||
|
+ if (term.scr == 0)
|
||||||
|
+ selscroll(orig, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
-tscrollup(int orig, int n)
|
||||||
|
+tscrollup(int orig, int n, int copyhist)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
Line temp;
|
||||||
|
|
||||||
|
LIMIT(n, 0, term.bot-orig+1);
|
||||||
|
|
||||||
|
+ if (copyhist) {
|
||||||
|
+ term.histi = (term.histi + 1) % HISTSIZE;
|
||||||
|
+ temp = term.hist[term.histi];
|
||||||
|
+ term.hist[term.histi] = term.line[orig];
|
||||||
|
+ 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);
|
||||||
|
tsetdirt(orig+n, term.bot);
|
||||||
|
|
||||||
|
@@ -1097,7 +1158,8 @@ tscrollup(int orig, int n)
|
||||||
|
term.line[i+n] = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
- selscroll(orig, -n);
|
||||||
|
+ if (term.scr == 0)
|
||||||
|
+ selscroll(orig, -n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
@@ -1126,7 +1188,7 @@ tnewline(int first_col)
|
||||||
|
int y = term.c.y;
|
||||||
|
|
||||||
|
if (y == term.bot) {
|
||||||
|
- tscrollup(term.top, 1);
|
||||||
|
+ tscrollup(term.top, 1, 1);
|
||||||
|
} else {
|
||||||
|
y++;
|
||||||
|
}
|
||||||
|
@@ -1291,14 +1353,14 @@ void
|
||||||
|
tinsertblankline(int n)
|
||||||
|
{
|
||||||
|
if (BETWEEN(term.c.y, term.top, term.bot))
|
||||||
|
- tscrolldown(term.c.y, n);
|
||||||
|
+ tscrolldown(term.c.y, n, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
tdeleteline(int n)
|
||||||
|
{
|
||||||
|
if (BETWEEN(term.c.y, term.top, term.bot))
|
||||||
|
- tscrollup(term.c.y, n);
|
||||||
|
+ tscrollup(term.c.y, n, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t
|
||||||
|
@@ -1735,11 +1797,11 @@ csihandle(void)
|
||||||
|
break;
|
||||||
|
case 'S': /* SU -- Scroll <n> line up */
|
||||||
|
DEFAULT(csiescseq.arg[0], 1);
|
||||||
|
- tscrollup(term.top, csiescseq.arg[0]);
|
||||||
|
+ tscrollup(term.top, csiescseq.arg[0], 0);
|
||||||
|
break;
|
||||||
|
case 'T': /* SD -- Scroll <n> line down */
|
||||||
|
DEFAULT(csiescseq.arg[0], 1);
|
||||||
|
- tscrolldown(term.top, csiescseq.arg[0]);
|
||||||
|
+ tscrolldown(term.top, csiescseq.arg[0], 0);
|
||||||
|
break;
|
||||||
|
case 'L': /* IL -- Insert <n> blank lines */
|
||||||
|
DEFAULT(csiescseq.arg[0], 1);
|
||||||
|
@@ -2251,7 +2313,7 @@ eschandle(uchar ascii)
|
||||||
|
return 0;
|
||||||
|
case 'D': /* IND -- Linefeed */
|
||||||
|
if (term.c.y == term.bot) {
|
||||||
|
- tscrollup(term.top, 1);
|
||||||
|
+ tscrollup(term.top, 1, 1);
|
||||||
|
} else {
|
||||||
|
tmoveto(term.c.x, term.c.y+1);
|
||||||
|
}
|
||||||
|
@@ -2264,7 +2326,7 @@ eschandle(uchar ascii)
|
||||||
|
break;
|
||||||
|
case 'M': /* RI -- Reverse index */
|
||||||
|
if (term.c.y == term.top) {
|
||||||
|
- tscrolldown(term.top, 1);
|
||||||
|
+ tscrolldown(term.top, 1, 1);
|
||||||
|
} else {
|
||||||
|
tmoveto(term.c.x, term.c.y-1);
|
||||||
|
}
|
||||||
|
@@ -2474,7 +2536,7 @@ twrite(const char *buf, int buflen, int show_ctrl)
|
||||||
|
void
|
||||||
|
tresize(int col, int row)
|
||||||
|
{
|
||||||
|
- int i;
|
||||||
|
+ int i, j;
|
||||||
|
int minrow = MIN(row, term.row);
|
||||||
|
int mincol = MIN(col, term.col);
|
||||||
|
int *bp;
|
||||||
|
@@ -2511,6 +2573,14 @@ tresize(int col, int row)
|
||||||
|
term.dirty = xrealloc(term.dirty, row * sizeof(*term.dirty));
|
||||||
|
term.tabs = xrealloc(term.tabs, col * sizeof(*term.tabs));
|
||||||
|
|
||||||
|
+ for (i = 0; i < HISTSIZE; i++) {
|
||||||
|
+ term.hist[i] = xrealloc(term.hist[i], col * sizeof(Glyph));
|
||||||
|
+ for (j = mincol; j < col; j++) {
|
||||||
|
+ term.hist[i][j] = term.c.attr;
|
||||||
|
+ term.hist[i][j].u = ' ';
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
/* resize each row to new width, zero-pad if needed */
|
||||||
|
for (i = 0; i < minrow; i++) {
|
||||||
|
term.line[i] = xrealloc(term.line[i], col * sizeof(Glyph));
|
||||||
|
@@ -2569,7 +2639,7 @@ drawregion(int x1, int y1, int x2, int y2)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
term.dirty[y] = 0;
|
||||||
|
- xdrawline(term.line[y], x1, y, x2);
|
||||||
|
+ xdrawline(TLINE(y), x1, y, x2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -2590,8 +2660,9 @@ draw(void)
|
||||||
|
cx--;
|
||||||
|
|
||||||
|
drawregion(0, 0, term.col, term.row);
|
||||||
|
- xdrawcursor(cx, term.c.y, term.line[term.c.y][cx],
|
||||||
|
- term.ocx, term.ocy, term.line[term.ocy][term.ocx]);
|
||||||
|
+ if (term.scr == 0)
|
||||||
|
+ xdrawcursor(cx, term.c.y, term.line[term.c.y][cx],
|
||||||
|
+ term.ocx, term.ocy, term.line[term.ocy][term.ocx]);
|
||||||
|
term.ocx = cx;
|
||||||
|
term.ocy = term.c.y;
|
||||||
|
xfinishdraw();
|
||||||
|
diff --git a/st.h b/st.h
|
||||||
|
index fa2eddf..adda2db 100644
|
||||||
|
--- a/st.h
|
||||||
|
+++ b/st.h
|
||||||
|
@@ -81,6 +81,8 @@ void die(const char *, ...);
|
||||||
|
void redraw(void);
|
||||||
|
void draw(void);
|
||||||
|
|
||||||
|
+void kscrolldown(const Arg *);
|
||||||
|
+void kscrollup(const Arg *);
|
||||||
|
void printscreen(const Arg *);
|
||||||
|
void printsel(const Arg *);
|
||||||
|
void sendbreak(const Arg *);
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
diff --git a/config.def.h b/config.def.h
|
||||||
|
index ec1b576..4b3bf15 100644
|
||||||
|
--- a/config.def.h
|
||||||
|
+++ b/config.def.h
|
||||||
|
@@ -163,6 +163,8 @@ static uint forcemousemod = ShiftMask;
|
||||||
|
*/
|
||||||
|
static MouseShortcut mshortcuts[] = {
|
||||||
|
/* mask button function argument release */
|
||||||
|
+ { ShiftMask, Button4, kscrollup, {.i = 1} },
|
||||||
|
+ { 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"} },
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
diff --git a/config.def.h b/config.def.h
|
||||||
|
index 4b3bf15..1986316 100644
|
||||||
|
--- a/config.def.h
|
||||||
|
+++ b/config.def.h
|
||||||
|
@@ -163,8 +163,8 @@ static uint forcemousemod = ShiftMask;
|
||||||
|
*/
|
||||||
|
static MouseShortcut mshortcuts[] = {
|
||||||
|
/* mask button function argument release */
|
||||||
|
- { ShiftMask, Button4, kscrollup, {.i = 1} },
|
||||||
|
- { ShiftMask, Button5, kscrolldown, {.i = 1} },
|
||||||
|
+ { XK_ANY_MOD, Button4, kscrollup, {.i = 1}, 0, /* !alt */ -1 },
|
||||||
|
+ { XK_ANY_MOD, Button5, kscrolldown, {.i = 1}, 0, /* !alt */ -1 },
|
||||||
|
{ XK_ANY_MOD, Button2, selpaste, {.i = 0}, 1 },
|
||||||
|
{ XK_ANY_MOD, Button4, ttysend, {.s = "\031"} },
|
||||||
|
{ XK_ANY_MOD, Button5, ttysend, {.s = "\005"} },
|
||||||
|
diff --git a/st.c b/st.c
|
||||||
|
index f8b6f67..dd4cb31 100644
|
||||||
|
--- st.c
|
||||||
|
+++ st.c
|
||||||
|
@@ -1045,6 +1045,11 @@ tnew(int col, int row)
|
||||||
|
treset();
|
||||||
|
}
|
||||||
|
|
||||||
|
+int tisaltscr(void)
|
||||||
|
+{
|
||||||
|
+ return IS_SET(MODE_ALTSCREEN);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
void
|
||||||
|
tswapscreen(void)
|
||||||
|
{
|
||||||
|
diff --git a/st.h b/st.h
|
||||||
|
index 1332cf1..f9ad815 100644
|
||||||
|
--- st.h
|
||||||
|
+++ st.h
|
||||||
|
@@ -89,6 +89,7 @@ void sendbreak(const Arg *);
|
||||||
|
void toggleprinter(const Arg *);
|
||||||
|
|
||||||
|
int tattrset(int);
|
||||||
|
+int tisaltscr(void);
|
||||||
|
void tnew(int, int);
|
||||||
|
void tresize(int, int);
|
||||||
|
void tsetdirtattr(int);
|
||||||
|
diff --git a/x.c b/x.c
|
||||||
|
index e5f1737..b8fbd7b 100644
|
||||||
|
--- x.c
|
||||||
|
+++ x.c
|
||||||
|
@@ -34,6 +34,7 @@ typedef struct {
|
||||||
|
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 {
|
||||||
|
@@ -446,6 +447,7 @@ mouseaction(XEvent *e, uint release)
|
||||||
|
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));
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
From 69cffc587b54b0a9cd81adb87abad8e526d5b25b Mon Sep 17 00:00:00 2001
|
||||||
|
From: "Avi Halachmi (:avih)" <avihpit@yahoo.com>
|
||||||
|
Date: Thu, 4 Jun 2020 17:35:08 +0300
|
||||||
|
Subject: [PATCH] support w3m images
|
||||||
|
|
||||||
|
w3m images are a hack which renders on top of the terminal's drawable,
|
||||||
|
which didn't work in st because when using double buffering, the front
|
||||||
|
buffer (on which w3m draws its images) is ignored, and st draws only
|
||||||
|
on the back buffer, which is then copied to the front buffer.
|
||||||
|
|
||||||
|
There's a patch to make it work at the FAQ already, but that patch
|
||||||
|
canceles double-buffering, which can have negative side effects on
|
||||||
|
some cases such as flickering.
|
||||||
|
|
||||||
|
This patch achieves the same goal but instead of canceling the double
|
||||||
|
buffer it first copies the front buffer to the back buffer.
|
||||||
|
|
||||||
|
This has the same issues as the FAQ patch in that the cursor line is
|
||||||
|
deleted at the image (because st renders always full lines), but
|
||||||
|
otherwise it's simpler and does keeps double buffering.
|
||||||
|
---
|
||||||
|
x.c | 2 ++
|
||||||
|
1 file changed, 2 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/x.c b/x.c
|
||||||
|
index e5f1737..b6ae162 100644
|
||||||
|
--- a/x.c
|
||||||
|
+++ b/x.c
|
||||||
|
@@ -1594,6 +1594,8 @@ xsettitle(char *p)
|
||||||
|
int
|
||||||
|
xstartdraw(void)
|
||||||
|
{
|
||||||
|
+ if (IS_SET(MODE_VISIBLE))
|
||||||
|
+ XCopyArea(xw.dpy, xw.win, xw.buf, dc.gc, 0, 0, win.w, win.h, 0, 0);
|
||||||
|
return IS_SET(MODE_VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
base-commit: 43a395ae91f7d67ce694e65edeaa7bbc720dd027
|
||||||
|
--
|
||||||
|
2.17.1
|
||||||
|
|
||||||
@@ -0,0 +1,184 @@
|
|||||||
|
From 2752a599ee01305a435729bfacf43b1dde7cf0ef Mon Sep 17 00:00:00 2001
|
||||||
|
From: Benji Encalada Mora <benji@encalada.dev>
|
||||||
|
Date: Thu, 4 Jun 2020 00:41:10 -0500
|
||||||
|
Subject: [PATCH] fix: replace xfps and actionfps variables
|
||||||
|
|
||||||
|
---
|
||||||
|
config.def.h | 36 ++++++++++++++++++++++++
|
||||||
|
x.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++---
|
||||||
|
2 files changed, 110 insertions(+), 4 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/config.def.h b/config.def.h
|
||||||
|
index 6f05dce..9b99782 100644
|
||||||
|
--- a/config.def.h
|
||||||
|
+++ b/config.def.h
|
||||||
|
@@ -168,6 +168,42 @@ static unsigned int defaultattr = 11;
|
||||||
|
*/
|
||||||
|
static uint forcemousemod = ShiftMask;
|
||||||
|
|
||||||
|
+/*
|
||||||
|
+ * Xresources preferences to load at startup
|
||||||
|
+ */
|
||||||
|
+ResourcePref resources[] = {
|
||||||
|
+ { "font", STRING, &font },
|
||||||
|
+ { "color0", STRING, &colorname[0] },
|
||||||
|
+ { "color1", STRING, &colorname[1] },
|
||||||
|
+ { "color2", STRING, &colorname[2] },
|
||||||
|
+ { "color3", STRING, &colorname[3] },
|
||||||
|
+ { "color4", STRING, &colorname[4] },
|
||||||
|
+ { "color5", STRING, &colorname[5] },
|
||||||
|
+ { "color6", STRING, &colorname[6] },
|
||||||
|
+ { "color7", STRING, &colorname[7] },
|
||||||
|
+ { "color8", STRING, &colorname[8] },
|
||||||
|
+ { "color9", STRING, &colorname[9] },
|
||||||
|
+ { "color10", STRING, &colorname[10] },
|
||||||
|
+ { "color11", STRING, &colorname[11] },
|
||||||
|
+ { "color12", STRING, &colorname[12] },
|
||||||
|
+ { "color13", STRING, &colorname[13] },
|
||||||
|
+ { "color14", STRING, &colorname[14] },
|
||||||
|
+ { "color15", STRING, &colorname[15] },
|
||||||
|
+ { "background", STRING, &colorname[256] },
|
||||||
|
+ { "foreground", STRING, &colorname[257] },
|
||||||
|
+ { "cursorColor", STRING, &colorname[258] },
|
||||||
|
+ { "termname", STRING, &termname },
|
||||||
|
+ { "shell", STRING, &shell },
|
||||||
|
+ { "minlatency", INTEGER, &minlatency },
|
||||||
|
+ { "maxlatency", INTEGER, &maxlatency },
|
||||||
|
+ { "blinktimeout", INTEGER, &blinktimeout },
|
||||||
|
+ { "bellvolume", INTEGER, &bellvolume },
|
||||||
|
+ { "tabspaces", INTEGER, &tabspaces },
|
||||||
|
+ { "borderpx", INTEGER, &borderpx },
|
||||||
|
+ { "cwscale", FLOAT, &cwscale },
|
||||||
|
+ { "chscale", FLOAT, &chscale },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* Internal mouse shortcuts.
|
||||||
|
* Beware that overloading Button1 will disable the selection.
|
||||||
|
diff --git a/x.c b/x.c
|
||||||
|
index 210f184..76f167f 100644
|
||||||
|
--- a/x.c
|
||||||
|
+++ b/x.c
|
||||||
|
@@ -14,6 +14,7 @@
|
||||||
|
#include <X11/keysym.h>
|
||||||
|
#include <X11/Xft/Xft.h>
|
||||||
|
#include <X11/XKBlib.h>
|
||||||
|
+#include <X11/Xresource.h>
|
||||||
|
|
||||||
|
char *argv0;
|
||||||
|
#include "arg.h"
|
||||||
|
@@ -45,6 +46,19 @@ typedef struct {
|
||||||
|
signed char appcursor; /* application cursor */
|
||||||
|
} Key;
|
||||||
|
|
||||||
|
+/* Xresources preferences */
|
||||||
|
+enum resource_type {
|
||||||
|
+ STRING = 0,
|
||||||
|
+ INTEGER = 1,
|
||||||
|
+ FLOAT = 2
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+typedef struct {
|
||||||
|
+ char *name;
|
||||||
|
+ enum resource_type type;
|
||||||
|
+ void *dst;
|
||||||
|
+} ResourcePref;
|
||||||
|
+
|
||||||
|
/* X modifiers */
|
||||||
|
#define XK_ANY_MOD UINT_MAX
|
||||||
|
#define XK_NO_MOD 0
|
||||||
|
@@ -828,8 +842,8 @@ xclear(int x1, int y1, int x2, int y2)
|
||||||
|
void
|
||||||
|
xhints(void)
|
||||||
|
{
|
||||||
|
- XClassHint class = {opt_name ? opt_name : termname,
|
||||||
|
- opt_class ? opt_class : termname};
|
||||||
|
+ XClassHint class = {opt_name ? opt_name : "st",
|
||||||
|
+ opt_class ? opt_class : "St"};
|
||||||
|
XWMHints wm = {.flags = InputHint, .input = 1};
|
||||||
|
XSizeHints *sizeh;
|
||||||
|
|
||||||
|
@@ -1104,8 +1118,6 @@ xinit(int cols, int rows)
|
||||||
|
pid_t thispid = getpid();
|
||||||
|
XColor xmousefg, xmousebg;
|
||||||
|
|
||||||
|
- if (!(xw.dpy = XOpenDisplay(NULL)))
|
||||||
|
- die("can't open display\n");
|
||||||
|
xw.scr = XDefaultScreen(xw.dpy);
|
||||||
|
xw.vis = XDefaultVisual(xw.dpy, xw.scr);
|
||||||
|
|
||||||
|
@@ -1964,6 +1976,59 @@ run(void)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+int
|
||||||
|
+resource_load(XrmDatabase db, char *name, enum resource_type rtype, void *dst)
|
||||||
|
+{
|
||||||
|
+ char **sdst = dst;
|
||||||
|
+ int *idst = dst;
|
||||||
|
+ float *fdst = dst;
|
||||||
|
+
|
||||||
|
+ char fullname[256];
|
||||||
|
+ char fullclass[256];
|
||||||
|
+ char *type;
|
||||||
|
+ XrmValue ret;
|
||||||
|
+
|
||||||
|
+ snprintf(fullname, sizeof(fullname), "%s.%s",
|
||||||
|
+ opt_name ? opt_name : "st", name);
|
||||||
|
+ snprintf(fullclass, sizeof(fullclass), "%s.%s",
|
||||||
|
+ opt_class ? opt_class : "St", name);
|
||||||
|
+ fullname[sizeof(fullname) - 1] = fullclass[sizeof(fullclass) - 1] = '\0';
|
||||||
|
+
|
||||||
|
+ XrmGetResource(db, fullname, fullclass, &type, &ret);
|
||||||
|
+ if (ret.addr == NULL || strncmp("String", type, 64))
|
||||||
|
+ return 1;
|
||||||
|
+
|
||||||
|
+ switch (rtype) {
|
||||||
|
+ case STRING:
|
||||||
|
+ *sdst = ret.addr;
|
||||||
|
+ break;
|
||||||
|
+ case INTEGER:
|
||||||
|
+ *idst = strtoul(ret.addr, NULL, 10);
|
||||||
|
+ break;
|
||||||
|
+ case FLOAT:
|
||||||
|
+ *fdst = strtof(ret.addr, NULL);
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void
|
||||||
|
+config_init(void)
|
||||||
|
+{
|
||||||
|
+ char *resm;
|
||||||
|
+ XrmDatabase db;
|
||||||
|
+ ResourcePref *p;
|
||||||
|
+
|
||||||
|
+ XrmInitialize();
|
||||||
|
+ resm = XResourceManagerString(xw.dpy);
|
||||||
|
+ if (!resm)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ db = XrmGetStringDatabase(resm);
|
||||||
|
+ for (p = resources; p < resources + LEN(resources); p++)
|
||||||
|
+ resource_load(db, p->name, p->type, p->dst);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
@@ -2037,6 +2102,11 @@ run:
|
||||||
|
|
||||||
|
setlocale(LC_CTYPE, "");
|
||||||
|
XSetLocaleModifiers("");
|
||||||
|
+
|
||||||
|
+ if(!(xw.dpy = XOpenDisplay(NULL)))
|
||||||
|
+ die("Can't open display\n");
|
||||||
|
+
|
||||||
|
+ config_init();
|
||||||
|
cols = MAX(cols, 1);
|
||||||
|
rows = MAX(rows, 1);
|
||||||
|
tnew(cols, rows);
|
||||||
|
--
|
||||||
|
2.26.2
|
||||||
|
|
||||||
@@ -0,0 +1,177 @@
|
|||||||
|
.TH ST 1 st\-VERSION
|
||||||
|
.SH NAME
|
||||||
|
st \- simple terminal
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.B st
|
||||||
|
.RB [ \-aiv ]
|
||||||
|
.RB [ \-c
|
||||||
|
.IR class ]
|
||||||
|
.RB [ \-f
|
||||||
|
.IR font ]
|
||||||
|
.RB [ \-g
|
||||||
|
.IR geometry ]
|
||||||
|
.RB [ \-n
|
||||||
|
.IR name ]
|
||||||
|
.RB [ \-o
|
||||||
|
.IR iofile ]
|
||||||
|
.RB [ \-T
|
||||||
|
.IR title ]
|
||||||
|
.RB [ \-t
|
||||||
|
.IR title ]
|
||||||
|
.RB [ \-l
|
||||||
|
.IR line ]
|
||||||
|
.RB [ \-w
|
||||||
|
.IR windowid ]
|
||||||
|
.RB [[ \-e ]
|
||||||
|
.IR command
|
||||||
|
.RI [ arguments ...]]
|
||||||
|
.PP
|
||||||
|
.B st
|
||||||
|
.RB [ \-aiv ]
|
||||||
|
.RB [ \-c
|
||||||
|
.IR class ]
|
||||||
|
.RB [ \-f
|
||||||
|
.IR font ]
|
||||||
|
.RB [ \-g
|
||||||
|
.IR geometry ]
|
||||||
|
.RB [ \-n
|
||||||
|
.IR name ]
|
||||||
|
.RB [ \-o
|
||||||
|
.IR iofile ]
|
||||||
|
.RB [ \-T
|
||||||
|
.IR title ]
|
||||||
|
.RB [ \-t
|
||||||
|
.IR title ]
|
||||||
|
.RB [ \-w
|
||||||
|
.IR windowid ]
|
||||||
|
.RB \-l
|
||||||
|
.IR line
|
||||||
|
.RI [ stty_args ...]
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.B st
|
||||||
|
is a simple terminal emulator.
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
.B \-a
|
||||||
|
disable alternate screens in terminal
|
||||||
|
.TP
|
||||||
|
.BI \-c " class"
|
||||||
|
defines the window class (default $TERM).
|
||||||
|
.TP
|
||||||
|
.BI \-f " font"
|
||||||
|
defines the
|
||||||
|
.I font
|
||||||
|
to use when st is run.
|
||||||
|
.TP
|
||||||
|
.BI \-g " geometry"
|
||||||
|
defines the X11 geometry string.
|
||||||
|
The form is [=][<cols>{xX}<rows>][{+-}<xoffset>{+-}<yoffset>]. See
|
||||||
|
.BR XParseGeometry (3)
|
||||||
|
for further details.
|
||||||
|
.TP
|
||||||
|
.B \-i
|
||||||
|
will fixate the position given with the -g option.
|
||||||
|
.TP
|
||||||
|
.BI \-n " name"
|
||||||
|
defines the window instance name (default $TERM).
|
||||||
|
.TP
|
||||||
|
.BI \-o " iofile"
|
||||||
|
writes all the I/O to
|
||||||
|
.I iofile.
|
||||||
|
This feature is useful when recording st sessions. A value of "-" means
|
||||||
|
standard output.
|
||||||
|
.TP
|
||||||
|
.BI \-T " title"
|
||||||
|
defines the window title (default 'st').
|
||||||
|
.TP
|
||||||
|
.BI \-t " title"
|
||||||
|
defines the window title (default 'st').
|
||||||
|
.TP
|
||||||
|
.BI \-w " windowid"
|
||||||
|
embeds st within the window identified by
|
||||||
|
.I windowid
|
||||||
|
.TP
|
||||||
|
.BI \-l " line"
|
||||||
|
use a tty
|
||||||
|
.I line
|
||||||
|
instead of a pseudo terminal.
|
||||||
|
.I line
|
||||||
|
should be a (pseudo-)serial device (e.g. /dev/ttyS0 on Linux for serial port
|
||||||
|
0).
|
||||||
|
When this flag is given
|
||||||
|
remaining arguments are used as flags for
|
||||||
|
.BR stty(1).
|
||||||
|
By default st initializes the serial line to 8 bits, no parity, 1 stop bit
|
||||||
|
and a 38400 baud rate. The speed is set by appending it as last argument
|
||||||
|
(e.g. 'st -l /dev/ttyS0 115200'). Arguments before the last one are
|
||||||
|
.BR stty(1)
|
||||||
|
flags. If you want to set odd parity on 115200 baud use for example 'st -l
|
||||||
|
/dev/ttyS0 parenb parodd 115200'. Set the number of bits by using for
|
||||||
|
example 'st -l /dev/ttyS0 cs7 115200'. See
|
||||||
|
.BR stty(1)
|
||||||
|
for more arguments and cases.
|
||||||
|
.TP
|
||||||
|
.B \-v
|
||||||
|
prints version information to stderr, then exits.
|
||||||
|
.TP
|
||||||
|
.BI \-e " command " [ " arguments " "... ]"
|
||||||
|
st executes
|
||||||
|
.I command
|
||||||
|
instead of the shell. If this is used it
|
||||||
|
.B must be the last option
|
||||||
|
on the command line, as in xterm / rxvt.
|
||||||
|
This option is only intended for compatibility,
|
||||||
|
and all the remaining arguments are used as a command
|
||||||
|
even without it.
|
||||||
|
.SH SHORTCUTS
|
||||||
|
.TP
|
||||||
|
.B Break
|
||||||
|
Send a break in the serial line.
|
||||||
|
Break key is obtained in PC keyboards
|
||||||
|
pressing at the same time control and pause.
|
||||||
|
.TP
|
||||||
|
.B Ctrl-Print Screen
|
||||||
|
Toggle if st should print to the
|
||||||
|
.I iofile.
|
||||||
|
.TP
|
||||||
|
.B Shift-Print Screen
|
||||||
|
Print the full screen to the
|
||||||
|
.I iofile.
|
||||||
|
.TP
|
||||||
|
.B Print Screen
|
||||||
|
Print the selection to the
|
||||||
|
.I iofile.
|
||||||
|
.TP
|
||||||
|
.B Ctrl-Shift-Page Up
|
||||||
|
Increase font size.
|
||||||
|
.TP
|
||||||
|
.B Ctrl-Shift-Page Down
|
||||||
|
Decrease font size.
|
||||||
|
.TP
|
||||||
|
.B Ctrl-Shift-Home
|
||||||
|
Reset to default font size.
|
||||||
|
.TP
|
||||||
|
.B Ctrl-Shift-y
|
||||||
|
Paste from primary selection (middle mouse button).
|
||||||
|
.TP
|
||||||
|
.B Ctrl-Shift-c
|
||||||
|
Copy the selected text to the clipboard selection.
|
||||||
|
.TP
|
||||||
|
.B Ctrl-Shift-v
|
||||||
|
Paste from the clipboard selection.
|
||||||
|
.SH CUSTOMIZATION
|
||||||
|
.B st
|
||||||
|
can be customized by creating a custom config.h and (re)compiling the source
|
||||||
|
code. This keeps it fast, secure and simple.
|
||||||
|
.SH AUTHORS
|
||||||
|
See the LICENSE file for the authors.
|
||||||
|
.SH LICENSE
|
||||||
|
See the LICENSE file for the terms of redistribution.
|
||||||
|
.SH SEE ALSO
|
||||||
|
.BR tabbed (1),
|
||||||
|
.BR utmp (1),
|
||||||
|
.BR stty (1),
|
||||||
|
.BR scroll (1)
|
||||||
|
.SH BUGS
|
||||||
|
See the TODO file in the distribution.
|
||||||
|
|
||||||
@@ -0,0 +1,145 @@
|
|||||||
|
/* See LICENSE for license details. */
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
/* macros */
|
||||||
|
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||||
|
#define MAX(a, b) ((a) < (b) ? (b) : (a))
|
||||||
|
#define LEN(a) (sizeof(a) / sizeof(a)[0])
|
||||||
|
#define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b))
|
||||||
|
#define DIVCEIL(n, d) (((n) + ((d) - 1)) / (d))
|
||||||
|
#define DEFAULT(a, b) (a) = (a) ? (a) : (b)
|
||||||
|
#define LIMIT(x, a, b) (x) = (x) < (a) ? (a) : (x) > (b) ? (b) : (x)
|
||||||
|
#define ATTRCMP(a, b) ((a).mode != (b).mode || (a).fg != (b).fg || \
|
||||||
|
(a).bg != (b).bg)
|
||||||
|
#define TIMEDIFF(t1, t2) ((t1.tv_sec-t2.tv_sec)*1000 + \
|
||||||
|
(t1.tv_nsec-t2.tv_nsec)/1E6)
|
||||||
|
#define MODBIT(x, set, bit) ((set) ? ((x) |= (bit)) : ((x) &= ~(bit)))
|
||||||
|
|
||||||
|
#define TRUECOLOR(r,g,b) (1 << 24 | (r) << 16 | (g) << 8 | (b))
|
||||||
|
#define IS_TRUECOL(x) (1 << 24 & (x))
|
||||||
|
|
||||||
|
enum glyph_attribute {
|
||||||
|
ATTR_NULL = 0,
|
||||||
|
ATTR_BOLD = 1 << 0,
|
||||||
|
ATTR_FAINT = 1 << 1,
|
||||||
|
ATTR_ITALIC = 1 << 2,
|
||||||
|
ATTR_UNDERLINE = 1 << 3,
|
||||||
|
ATTR_BLINK = 1 << 4,
|
||||||
|
ATTR_REVERSE = 1 << 5,
|
||||||
|
ATTR_INVISIBLE = 1 << 6,
|
||||||
|
ATTR_STRUCK = 1 << 7,
|
||||||
|
ATTR_WRAP = 1 << 8,
|
||||||
|
ATTR_WIDE = 1 << 9,
|
||||||
|
ATTR_WDUMMY = 1 << 10,
|
||||||
|
ATTR_BOXDRAW = 1 << 11,
|
||||||
|
ATTR_BOLD_FAINT = ATTR_BOLD | ATTR_FAINT,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum selection_mode {
|
||||||
|
SEL_IDLE = 0,
|
||||||
|
SEL_EMPTY = 1,
|
||||||
|
SEL_READY = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
enum selection_type {
|
||||||
|
SEL_REGULAR = 1,
|
||||||
|
SEL_RECTANGULAR = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
enum selection_snap {
|
||||||
|
SNAP_WORD = 1,
|
||||||
|
SNAP_LINE = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef unsigned char uchar;
|
||||||
|
typedef unsigned int uint;
|
||||||
|
typedef unsigned long ulong;
|
||||||
|
typedef unsigned short ushort;
|
||||||
|
|
||||||
|
typedef uint_least32_t Rune;
|
||||||
|
|
||||||
|
#define Glyph Glyph_
|
||||||
|
typedef struct {
|
||||||
|
Rune u; /* character code */
|
||||||
|
ushort mode; /* attribute flags */
|
||||||
|
uint32_t fg; /* foreground */
|
||||||
|
uint32_t bg; /* background */
|
||||||
|
} Glyph;
|
||||||
|
|
||||||
|
typedef Glyph *Line;
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
int i;
|
||||||
|
uint ui;
|
||||||
|
float f;
|
||||||
|
const void *v;
|
||||||
|
const char *s;
|
||||||
|
} Arg;
|
||||||
|
|
||||||
|
void die(const char *, ...);
|
||||||
|
void redraw(void);
|
||||||
|
void draw(void);
|
||||||
|
|
||||||
|
void opencopied(const Arg *);
|
||||||
|
void kscrolldown(const Arg *);
|
||||||
|
void kscrollup(const Arg *);
|
||||||
|
void printscreen(const Arg *);
|
||||||
|
void printsel(const Arg *);
|
||||||
|
void sendbreak(const Arg *);
|
||||||
|
void toggleprinter(const Arg *);
|
||||||
|
void copyurl(const Arg *);
|
||||||
|
|
||||||
|
int tattrset(int);
|
||||||
|
int tisaltscr(void);
|
||||||
|
void tnew(int, int);
|
||||||
|
void tresize(int, int);
|
||||||
|
void tsetdirtattr(int);
|
||||||
|
void ttyhangup(void);
|
||||||
|
int ttynew(const char *, char *, const char *, char **);
|
||||||
|
size_t ttyread(void);
|
||||||
|
void ttyresize(int, int);
|
||||||
|
void ttywrite(const char *, size_t, int);
|
||||||
|
|
||||||
|
void resettitle(void);
|
||||||
|
|
||||||
|
void selclear(void);
|
||||||
|
void selinit(void);
|
||||||
|
void selstart(int, int, int);
|
||||||
|
void selextend(int, int, int, int);
|
||||||
|
int selected(int, int);
|
||||||
|
char *getsel(void);
|
||||||
|
|
||||||
|
size_t utf8encode(Rune, char *);
|
||||||
|
|
||||||
|
void *xmalloc(size_t);
|
||||||
|
void *xrealloc(void *, size_t);
|
||||||
|
char *xstrdup(const char *);
|
||||||
|
int xgetcolor(int x, unsigned char *r, unsigned char *g, unsigned char *b);
|
||||||
|
|
||||||
|
int trt_kbdselect(KeySym, char *, int);
|
||||||
|
|
||||||
|
int isboxdraw(Rune);
|
||||||
|
ushort boxdrawindex(const Glyph *);
|
||||||
|
#ifdef XFT_VERSION
|
||||||
|
/* only exposed to x.c, otherwise we'll need Xft.h for the types */
|
||||||
|
void boxdraw_xinit(Display *, Colormap, XftDraw *, Visual *);
|
||||||
|
void drawboxes(int, int, int, int, XftColor *, XftColor *, const XftGlyphFontSpec *, int);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* config.h globals */
|
||||||
|
extern char *utmp;
|
||||||
|
extern char *scroll;
|
||||||
|
extern char *stty_args;
|
||||||
|
extern char *vtiden;
|
||||||
|
extern wchar_t *worddelimiters;
|
||||||
|
extern int allowaltscreen;
|
||||||
|
extern int allowwindowops;
|
||||||
|
extern char *termname;
|
||||||
|
extern unsigned int tabspaces;
|
||||||
|
extern unsigned int defaultfg;
|
||||||
|
extern unsigned int defaultbg;
|
||||||
|
extern unsigned int defaultcs;
|
||||||
|
extern float alpha;
|
||||||
|
extern const int boxdraw, boxdraw_bold, boxdraw_braille;
|
||||||
+244
@@ -0,0 +1,244 @@
|
|||||||
|
st-mono| simpleterm monocolor,
|
||||||
|
acsc=+C\,D-A.B0E``aaffgghFiGjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~,
|
||||||
|
am,
|
||||||
|
bce,
|
||||||
|
bel=^G,
|
||||||
|
blink=\E[5m,
|
||||||
|
bold=\E[1m,
|
||||||
|
cbt=\E[Z,
|
||||||
|
cvvis=\E[?25h,
|
||||||
|
civis=\E[?25l,
|
||||||
|
clear=\E[H\E[2J,
|
||||||
|
cnorm=\E[?12l\E[?25h,
|
||||||
|
colors#2,
|
||||||
|
cols#80,
|
||||||
|
cr=^M,
|
||||||
|
csr=\E[%i%p1%d;%p2%dr,
|
||||||
|
cub=\E[%p1%dD,
|
||||||
|
cub1=^H,
|
||||||
|
cud1=^J,
|
||||||
|
cud=\E[%p1%dB,
|
||||||
|
cuf1=\E[C,
|
||||||
|
cuf=\E[%p1%dC,
|
||||||
|
cup=\E[%i%p1%d;%p2%dH,
|
||||||
|
cuu1=\E[A,
|
||||||
|
cuu=\E[%p1%dA,
|
||||||
|
dch=\E[%p1%dP,
|
||||||
|
dch1=\E[P,
|
||||||
|
dim=\E[2m,
|
||||||
|
dl=\E[%p1%dM,
|
||||||
|
dl1=\E[M,
|
||||||
|
ech=\E[%p1%dX,
|
||||||
|
ed=\E[J,
|
||||||
|
el=\E[K,
|
||||||
|
el1=\E[1K,
|
||||||
|
enacs=\E)0,
|
||||||
|
flash=\E[?5h$<80/>\E[?5l,
|
||||||
|
fsl=^G,
|
||||||
|
home=\E[H,
|
||||||
|
hpa=\E[%i%p1%dG,
|
||||||
|
hs,
|
||||||
|
ht=^I,
|
||||||
|
hts=\EH,
|
||||||
|
ich=\E[%p1%d@,
|
||||||
|
il1=\E[L,
|
||||||
|
il=\E[%p1%dL,
|
||||||
|
ind=^J,
|
||||||
|
indn=\E[%p1%dS,
|
||||||
|
invis=\E[8m,
|
||||||
|
is2=\E[4l\E>\E[?1034l,
|
||||||
|
it#8,
|
||||||
|
kel=\E[1;2F,
|
||||||
|
ked=\E[1;5F,
|
||||||
|
ka1=\E[1~,
|
||||||
|
ka3=\E[5~,
|
||||||
|
kc1=\E[4~,
|
||||||
|
kc3=\E[6~,
|
||||||
|
kbs=\177,
|
||||||
|
kcbt=\E[Z,
|
||||||
|
kb2=\EOu,
|
||||||
|
kcub1=\EOD,
|
||||||
|
kcud1=\EOB,
|
||||||
|
kcuf1=\EOC,
|
||||||
|
kcuu1=\EOA,
|
||||||
|
kDC=\E[3;2~,
|
||||||
|
kent=\EOM,
|
||||||
|
kEND=\E[1;2F,
|
||||||
|
kIC=\E[2;2~,
|
||||||
|
kNXT=\E[6;2~,
|
||||||
|
kPRV=\E[5;2~,
|
||||||
|
kHOM=\E[1;2H,
|
||||||
|
kLFT=\E[1;2D,
|
||||||
|
kRIT=\E[1;2C,
|
||||||
|
kind=\E[1;2B,
|
||||||
|
kri=\E[1;2A,
|
||||||
|
kclr=\E[3;5~,
|
||||||
|
kdl1=\E[3;2~,
|
||||||
|
kdch1=\E[3~,
|
||||||
|
kich1=\E[2~,
|
||||||
|
kend=\E[4~,
|
||||||
|
kf1=\EOP,
|
||||||
|
kf2=\EOQ,
|
||||||
|
kf3=\EOR,
|
||||||
|
kf4=\EOS,
|
||||||
|
kf5=\E[15~,
|
||||||
|
kf6=\E[17~,
|
||||||
|
kf7=\E[18~,
|
||||||
|
kf8=\E[19~,
|
||||||
|
kf9=\E[20~,
|
||||||
|
kf10=\E[21~,
|
||||||
|
kf11=\E[23~,
|
||||||
|
kf12=\E[24~,
|
||||||
|
kf13=\E[1;2P,
|
||||||
|
kf14=\E[1;2Q,
|
||||||
|
kf15=\E[1;2R,
|
||||||
|
kf16=\E[1;2S,
|
||||||
|
kf17=\E[15;2~,
|
||||||
|
kf18=\E[17;2~,
|
||||||
|
kf19=\E[18;2~,
|
||||||
|
kf20=\E[19;2~,
|
||||||
|
kf21=\E[20;2~,
|
||||||
|
kf22=\E[21;2~,
|
||||||
|
kf23=\E[23;2~,
|
||||||
|
kf24=\E[24;2~,
|
||||||
|
kf25=\E[1;5P,
|
||||||
|
kf26=\E[1;5Q,
|
||||||
|
kf27=\E[1;5R,
|
||||||
|
kf28=\E[1;5S,
|
||||||
|
kf29=\E[15;5~,
|
||||||
|
kf30=\E[17;5~,
|
||||||
|
kf31=\E[18;5~,
|
||||||
|
kf32=\E[19;5~,
|
||||||
|
kf33=\E[20;5~,
|
||||||
|
kf34=\E[21;5~,
|
||||||
|
kf35=\E[23;5~,
|
||||||
|
kf36=\E[24;5~,
|
||||||
|
kf37=\E[1;6P,
|
||||||
|
kf38=\E[1;6Q,
|
||||||
|
kf39=\E[1;6R,
|
||||||
|
kf40=\E[1;6S,
|
||||||
|
kf41=\E[15;6~,
|
||||||
|
kf42=\E[17;6~,
|
||||||
|
kf43=\E[18;6~,
|
||||||
|
kf44=\E[19;6~,
|
||||||
|
kf45=\E[20;6~,
|
||||||
|
kf46=\E[21;6~,
|
||||||
|
kf47=\E[23;6~,
|
||||||
|
kf48=\E[24;6~,
|
||||||
|
kf49=\E[1;3P,
|
||||||
|
kf50=\E[1;3Q,
|
||||||
|
kf51=\E[1;3R,
|
||||||
|
kf52=\E[1;3S,
|
||||||
|
kf53=\E[15;3~,
|
||||||
|
kf54=\E[17;3~,
|
||||||
|
kf55=\E[18;3~,
|
||||||
|
kf56=\E[19;3~,
|
||||||
|
kf57=\E[20;3~,
|
||||||
|
kf58=\E[21;3~,
|
||||||
|
kf59=\E[23;3~,
|
||||||
|
kf60=\E[24;3~,
|
||||||
|
kf61=\E[1;4P,
|
||||||
|
kf62=\E[1;4Q,
|
||||||
|
kf63=\E[1;4R,
|
||||||
|
khome=\E[1~,
|
||||||
|
kil1=\E[2;5~,
|
||||||
|
krmir=\E[2;2~,
|
||||||
|
knp=\E[6~,
|
||||||
|
kmous=\E[M,
|
||||||
|
kpp=\E[5~,
|
||||||
|
lines#24,
|
||||||
|
mir,
|
||||||
|
msgr,
|
||||||
|
npc,
|
||||||
|
op=\E[39;49m,
|
||||||
|
pairs#64,
|
||||||
|
mc0=\E[i,
|
||||||
|
mc4=\E[4i,
|
||||||
|
mc5=\E[5i,
|
||||||
|
rc=\E8,
|
||||||
|
rev=\E[7m,
|
||||||
|
ri=\EM,
|
||||||
|
rin=\E[%p1%dT,
|
||||||
|
ritm=\E[23m,
|
||||||
|
rmacs=\E(B,
|
||||||
|
rmcup=\E[?1049l,
|
||||||
|
rmir=\E[4l,
|
||||||
|
rmkx=\E[?1l\E>,
|
||||||
|
rmso=\E[27m,
|
||||||
|
rmul=\E[24m,
|
||||||
|
rs1=\Ec,
|
||||||
|
rs2=\E[4l\E>\E[?1034l,
|
||||||
|
sc=\E7,
|
||||||
|
sitm=\E[3m,
|
||||||
|
sgr0=\E[0m,
|
||||||
|
smacs=\E(0,
|
||||||
|
smcup=\E[?1049h,
|
||||||
|
smir=\E[4h,
|
||||||
|
smkx=\E[?1h\E=,
|
||||||
|
smso=\E[7m,
|
||||||
|
smul=\E[4m,
|
||||||
|
tbc=\E[3g,
|
||||||
|
tsl=\E]0;,
|
||||||
|
xenl,
|
||||||
|
vpa=\E[%i%p1%dd,
|
||||||
|
# XTerm extensions
|
||||||
|
rmxx=\E[29m,
|
||||||
|
smxx=\E[9m,
|
||||||
|
BE=\E[?2004h,
|
||||||
|
BD=\E[?2004l,
|
||||||
|
PS=\E[200~,
|
||||||
|
PE=\E[201~,
|
||||||
|
# disabled rep for now: causes some issues with older ncurses versions.
|
||||||
|
# rep=%p1%c\E[%p2%{1}%-%db,
|
||||||
|
# tmux extensions, see TERMINFO EXTENSIONS in tmux(1)
|
||||||
|
Tc,
|
||||||
|
Ms=\E]52;%p1%s;%p2%s\007,
|
||||||
|
Se=\E[2 q,
|
||||||
|
Ss=\E[%p1%d q,
|
||||||
|
Sync=\EP=%p1%ds\E\\,
|
||||||
|
|
||||||
|
st| simpleterm,
|
||||||
|
use=st-mono,
|
||||||
|
colors#8,
|
||||||
|
setab=\E[4%p1%dm,
|
||||||
|
setaf=\E[3%p1%dm,
|
||||||
|
setb=\E[4%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m,
|
||||||
|
setf=\E[3%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m,
|
||||||
|
sgr=%?%p9%t\E(0%e\E(B%;\E[0%?%p6%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m,
|
||||||
|
|
||||||
|
st-256color| simpleterm with 256 colors,
|
||||||
|
use=st,
|
||||||
|
ccc,
|
||||||
|
colors#256,
|
||||||
|
oc=\E]104\007,
|
||||||
|
pairs#32767,
|
||||||
|
# Nicked from xterm-256color
|
||||||
|
initc=\E]4;%p1%d;rgb\:%p2%{255}%*%{1000}%/%2.2X/%p3%{255}%*%{1000}%/%2.2X/%p4%{255}%*%{1000}%/%2.2X\E\\,
|
||||||
|
setab=\E[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m,
|
||||||
|
setaf=\E[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m,
|
||||||
|
|
||||||
|
st-meta| simpleterm with meta key,
|
||||||
|
use=st,
|
||||||
|
km,
|
||||||
|
rmm=\E[?1034l,
|
||||||
|
smm=\E[?1034h,
|
||||||
|
rs2=\E[4l\E>\E[?1034h,
|
||||||
|
is2=\E[4l\E>\E[?1034h,
|
||||||
|
|
||||||
|
st-meta-256color| simpleterm with meta key and 256 colors,
|
||||||
|
use=st-256color,
|
||||||
|
km,
|
||||||
|
rmm=\E[?1034l,
|
||||||
|
smm=\E[?1034h,
|
||||||
|
rs2=\E[4l\E>\E[?1034h,
|
||||||
|
is2=\E[4l\E>\E[?1034h,
|
||||||
|
|
||||||
|
st-bs| simpleterm with backspace as backspace,
|
||||||
|
use=st,
|
||||||
|
kbs=\010,
|
||||||
|
kdch1=\177,
|
||||||
|
|
||||||
|
st-bs-256color| simpleterm with backspace as backspace and 256colors,
|
||||||
|
use=st-256color,
|
||||||
|
kbs=\010,
|
||||||
|
kdch1=\177,
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
/* See LICENSE for license details. */
|
||||||
|
|
||||||
|
enum win_mode {
|
||||||
|
MODE_VISIBLE = 1 << 0,
|
||||||
|
MODE_FOCUSED = 1 << 1,
|
||||||
|
MODE_APPKEYPAD = 1 << 2,
|
||||||
|
MODE_MOUSEBTN = 1 << 3,
|
||||||
|
MODE_MOUSEMOTION = 1 << 4,
|
||||||
|
MODE_REVERSE = 1 << 5,
|
||||||
|
MODE_KBDLOCK = 1 << 6,
|
||||||
|
MODE_HIDE = 1 << 7,
|
||||||
|
MODE_APPCURSOR = 1 << 8,
|
||||||
|
MODE_MOUSESGR = 1 << 9,
|
||||||
|
MODE_8BIT = 1 << 10,
|
||||||
|
MODE_BLINK = 1 << 11,
|
||||||
|
MODE_FBLINK = 1 << 12,
|
||||||
|
MODE_FOCUS = 1 << 13,
|
||||||
|
MODE_MOUSEX10 = 1 << 14,
|
||||||
|
MODE_MOUSEMANY = 1 << 15,
|
||||||
|
MODE_BRCKTPASTE = 1 << 16,
|
||||||
|
MODE_NUMLOCK = 1 << 17,
|
||||||
|
MODE_MOUSE = MODE_MOUSEBTN|MODE_MOUSEMOTION|MODE_MOUSEX10\
|
||||||
|
|MODE_MOUSEMANY,
|
||||||
|
MODE_KBDSELECT = 1 << 18,
|
||||||
|
};
|
||||||
|
|
||||||
|
void xbell(void);
|
||||||
|
void xclipcopy(void);
|
||||||
|
void xdrawcursor(int, int, Glyph, int, int, Glyph);
|
||||||
|
void xdrawline(Line, int, int, int);
|
||||||
|
void xfinishdraw(void);
|
||||||
|
void xloadcols(void);
|
||||||
|
int xsetcolorname(int, const char *);
|
||||||
|
void xseticontitle(char *);
|
||||||
|
void xsettitle(char *);
|
||||||
|
int xsetcursor(int);
|
||||||
|
void xsetmode(int, unsigned int);
|
||||||
|
void xsetpointermotion(int);
|
||||||
|
void xsetsel(char *);
|
||||||
|
int xstartdraw(void);
|
||||||
|
void toggle_winmode(int);
|
||||||
|
void keyboard_select(const Arg *);
|
||||||
|
void xximspot(int, int);
|
||||||
Reference in New Issue
Block a user