remove .local/src
This commit is contained in:
parent
f0854e537f
commit
aa803b31a2
70 changed files with 1 additions and 9511 deletions
.local/src2
dmenu
FUNDING.ymlLICENSEMakefileREADME.mdarg.hconfig.hconfig.mkdmenudmenu.1dmenu.cdmenu.odmenu_pathdmenu_rundrw.cdrw.hdrw.osteststest.1stest.cstest.outil.cutil.hutil.o
dwm
FUNDING.ymlLICENSEMakefilePKGBUILDREADME.mdcompile_commands.jsonconfig.hconfig.mkdrw.cdrw.hdrw.odwmdwm.1dwm.cdwm.oshiftview.ctransient.cutil.cutil.hutil.ovanitygaps.c
dwmblocks
slock
|
@ -1,3 +0,0 @@
|
||||||
github: lukesmithxyz
|
|
||||||
custom: ["https://lukesmith.xyz/donate", "https://paypal.me/lukemsmith", "https://lukesmith.xyz/crypto"]
|
|
||||||
patreon: lukesmith
|
|
|
@ -1,30 +0,0 @@
|
||||||
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.
|
|
|
@ -1,64 +0,0 @@
|
||||||
# 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 *.rej *.orig
|
|
||||||
|
|
||||||
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
|
|
|
@ -1,16 +0,0 @@
|
||||||
# Luke's dmenu
|
|
||||||
|
|
||||||
Extra stuff added to vanilla dmenu:
|
|
||||||
|
|
||||||
- reads Xresources (ergo pywal compatible)
|
|
||||||
- alpha patch, which importantly allows this build to be embedded in transparent st
|
|
||||||
- can view color characters like emoji (libxft-bgra is required for this reason)
|
|
||||||
- `-P` for password mode: hide user input
|
|
||||||
- `-r` to reject non-matching input
|
|
||||||
- dmenu options are mouse clickable
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
You must have `libxft-bgra` installed until the libxft upstream is fixed.
|
|
||||||
|
|
||||||
After making any config changes that you want, but `make`, `sudo make install` it.
|
|
|
@ -1,49 +0,0 @@
|
||||||
/*
|
|
||||||
* 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
|
|
|
@ -1,33 +0,0 @@
|
||||||
/* 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",
|
|
||||||
"JoyPixels:pixelsize=8:antialias=true:autohint=true"
|
|
||||||
};
|
|
||||||
static const unsigned int bgalpha = 0xe0;
|
|
||||||
static const unsigned int fgalpha = OPAQUE;
|
|
||||||
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] = {
|
|
||||||
/* fgalpha bgalphga */
|
|
||||||
[SchemeNorm] = { fgalpha, bgalpha },
|
|
||||||
[SchemeSel] = { fgalpha, bgalpha },
|
|
||||||
[SchemeOut] = { fgalpha, bgalpha },
|
|
||||||
};
|
|
||||||
|
|
||||||
/* -l option; if nonzero, dmenu uses vertical list with given number of lines */
|
|
||||||
static unsigned int lines = 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Characters not considered part of a word while deleting words
|
|
||||||
* for example: " /?\"&[]"
|
|
||||||
*/
|
|
||||||
static const char worddelimiters[] = " ";
|
|
|
@ -1,31 +0,0 @@
|
||||||
# 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
|
|
Binary file not shown.
|
@ -1,200 +0,0 @@
|
||||||
.TH DMENU 1 dmenu\-VERSION
|
|
||||||
.SH NAME
|
|
||||||
dmenu \- dynamic menu
|
|
||||||
.SH SYNOPSIS
|
|
||||||
.B dmenu
|
|
||||||
.RB [ \-bfirvP ]
|
|
||||||
.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
|
|
||||||
.B \-P
|
|
||||||
dmenu will not directly display the keyboard input, but instead replace it with dots. All data from stdin will be ignored.
|
|
||||||
.TP
|
|
||||||
.B \-r
|
|
||||||
dmenu will reject any input which would result in no matching option left.
|
|
||||||
.TP
|
|
||||||
.BI \-l " lines"
|
|
||||||
dmenu lists items vertically, 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)
|
|
|
@ -1,995 +0,0 @@
|
||||||
/* 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/Xutil.h>
|
|
||||||
#ifdef XINERAMA
|
|
||||||
#include <X11/extensions/Xinerama.h>
|
|
||||||
#endif
|
|
||||||
#include <X11/Xft/Xft.h>
|
|
||||||
#include <X11/Xresource.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 opaqueness */
|
|
||||||
#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, passwd = 0;
|
|
||||||
static int lrpad; /* sum of left and right padding */
|
|
||||||
static int reject_no_match = 0;
|
|
||||||
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 int usergb = 0;
|
|
||||||
static Visual *visual;
|
|
||||||
static int depth;
|
|
||||||
static Colormap cmap;
|
|
||||||
static Clr *scheme[SchemeLast];
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
static int (*fstrncmp)(const char *, const char *, size_t) = strncmp;
|
|
||||||
static char *(*fstrstr)(const char *, const char *) = strstr;
|
|
||||||
|
|
||||||
|
|
||||||
static 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);
|
|
||||||
usergb = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
XFree(infos);
|
|
||||||
|
|
||||||
if (! visual) {
|
|
||||||
visual = DefaultVisual(dpy, screen);
|
|
||||||
depth = DefaultDepth(dpy, screen);
|
|
||||||
cmap = DefaultColormap(dpy, screen);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 * 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 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;
|
|
||||||
char *censort;
|
|
||||||
|
|
||||||
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]);
|
|
||||||
if (passwd) {
|
|
||||||
censort = ecalloc(1, sizeof(text));
|
|
||||||
memset(censort, '.', strlen(text));
|
|
||||||
drw_text(drw, x, 0, w, bh, lrpad / 2, censort, 0);
|
|
||||||
free(censort);
|
|
||||||
} else 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 vertical list */
|
|
||||||
for (item = curr; item != next; item = item->right)
|
|
||||||
drawitem(item, x, y += bh, mw - x);
|
|
||||||
} 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;
|
|
||||||
|
|
||||||
static char last[BUFSIZ] = "";
|
|
||||||
if(reject_no_match) {
|
|
||||||
/* store last text value in case we need to revert it */
|
|
||||||
memcpy(last, text, BUFSIZ);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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();
|
|
||||||
|
|
||||||
if(!matches && reject_no_match) {
|
|
||||||
/* revert to last text value if theres no match */
|
|
||||||
memcpy(text, last, BUFSIZ);
|
|
||||||
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:
|
|
||||||
movewordedge(-1);
|
|
||||||
goto draw;
|
|
||||||
case XK_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:
|
|
||||||
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:
|
|
||||||
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:
|
|
||||||
if (sel == matches) {
|
|
||||||
cursor = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
sel = curr = matches;
|
|
||||||
calcoffsets();
|
|
||||||
break;
|
|
||||||
case XK_Left:
|
|
||||||
if (cursor > 0 && (!sel || !sel->left || lines > 0)) {
|
|
||||||
cursor = nextrune(-1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (lines > 0)
|
|
||||||
return;
|
|
||||||
/* fallthrough */
|
|
||||||
case XK_Up:
|
|
||||||
if (sel && sel->left && (sel = sel->left)->right == curr) {
|
|
||||||
curr = prev;
|
|
||||||
calcoffsets();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case XK_Next:
|
|
||||||
if (!next)
|
|
||||||
return;
|
|
||||||
sel = curr = next;
|
|
||||||
calcoffsets();
|
|
||||||
break;
|
|
||||||
case XK_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:
|
|
||||||
if (text[cursor] != '\0') {
|
|
||||||
cursor = nextrune(+1);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (lines > 0)
|
|
||||||
return;
|
|
||||||
/* fallthrough */
|
|
||||||
case XK_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
|
|
||||||
buttonpress(XEvent *e)
|
|
||||||
{
|
|
||||||
struct item *item;
|
|
||||||
XButtonPressedEvent *ev = &e->xbutton;
|
|
||||||
int x = 0, y = 0, h = bh, w;
|
|
||||||
|
|
||||||
if (ev->window != win)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* right-click: exit */
|
|
||||||
if (ev->button == Button3)
|
|
||||||
exit(1);
|
|
||||||
|
|
||||||
if (prompt && *prompt)
|
|
||||||
x += promptw;
|
|
||||||
|
|
||||||
/* input field */
|
|
||||||
w = (lines > 0 || !matches) ? mw - x : inputw;
|
|
||||||
|
|
||||||
/* left-click on input: clear input,
|
|
||||||
* NOTE: if there is no left-arrow the space for < is reserved so
|
|
||||||
* add that to the input width */
|
|
||||||
if (ev->button == Button1 &&
|
|
||||||
((lines <= 0 && ev->x >= 0 && ev->x <= x + w +
|
|
||||||
((!prev || !curr->left) ? TEXTW("<") : 0)) ||
|
|
||||||
(lines > 0 && ev->y >= y && ev->y <= y + h))) {
|
|
||||||
insert(NULL, -cursor);
|
|
||||||
drawmenu();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/* middle-mouse click: paste selection */
|
|
||||||
if (ev->button == Button2) {
|
|
||||||
XConvertSelection(dpy, (ev->state & ShiftMask) ? clip : XA_PRIMARY,
|
|
||||||
utf8, utf8, win, CurrentTime);
|
|
||||||
drawmenu();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/* scroll up */
|
|
||||||
if (ev->button == Button4 && prev) {
|
|
||||||
sel = curr = prev;
|
|
||||||
calcoffsets();
|
|
||||||
drawmenu();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/* scroll down */
|
|
||||||
if (ev->button == Button5 && next) {
|
|
||||||
sel = curr = next;
|
|
||||||
calcoffsets();
|
|
||||||
drawmenu();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (ev->button != Button1)
|
|
||||||
return;
|
|
||||||
if (ev->state & ~ControlMask)
|
|
||||||
return;
|
|
||||||
if (lines > 0) {
|
|
||||||
/* vertical list: (ctrl)left-click on item */
|
|
||||||
w = mw - x;
|
|
||||||
for (item = curr; item != next; item = item->right) {
|
|
||||||
y += h;
|
|
||||||
if (ev->y >= y && ev->y <= (y + h)) {
|
|
||||||
puts(item->text);
|
|
||||||
if (!(ev->state & ControlMask))
|
|
||||||
exit(0);
|
|
||||||
sel = item;
|
|
||||||
if (sel) {
|
|
||||||
sel->out = 1;
|
|
||||||
drawmenu();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (matches) {
|
|
||||||
/* left-click on left arrow */
|
|
||||||
x += inputw;
|
|
||||||
w = TEXTW("<");
|
|
||||||
if (prev && curr->left) {
|
|
||||||
if (ev->x >= x && ev->x <= x + w) {
|
|
||||||
sel = curr = prev;
|
|
||||||
calcoffsets();
|
|
||||||
drawmenu();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* horizontal list: (ctrl)left-click on item */
|
|
||||||
for (item = curr; item != next; item = item->right) {
|
|
||||||
x += w;
|
|
||||||
w = MIN(TEXTW(item->text), mw - x - TEXTW(">"));
|
|
||||||
if (ev->x >= x && ev->x <= x + w) {
|
|
||||||
puts(item->text);
|
|
||||||
if (!(ev->state & ControlMask))
|
|
||||||
exit(0);
|
|
||||||
sel = item;
|
|
||||||
if (sel) {
|
|
||||||
sel->out = 1;
|
|
||||||
drawmenu();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* left-click on right arrow */
|
|
||||||
w = TEXTW(">");
|
|
||||||
x = mw - w;
|
|
||||||
if (next && ev->x >= x && ev->x <= x + w) {
|
|
||||||
sel = curr = next;
|
|
||||||
calcoffsets();
|
|
||||||
drawmenu();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
if(passwd){
|
|
||||||
inputw = lines = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 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 ButtonPress:
|
|
||||||
buttonpress(&ev);
|
|
||||||
break;
|
|
||||||
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[j], 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;
|
|
||||||
#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;
|
|
||||||
|
|
||||||
x = info[i].x_org;
|
|
||||||
y = info[i].y_org + (topbar ? 0 : info[i].height - mh);
|
|
||||||
mw = info[i].width;
|
|
||||||
XFree(info);
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
promptw = (prompt && *prompt) ? TEXTW(prompt) - lrpad / 4 : 0;
|
|
||||||
inputw = MIN(inputw, mw/3);
|
|
||||||
match();
|
|
||||||
|
|
||||||
/* create menu window */
|
|
||||||
swa.override_redirect = True;
|
|
||||||
swa.background_pixel = scheme[SchemeNorm][ColBg].pixel;
|
|
||||||
swa.border_pixel = 0;
|
|
||||||
swa.colormap = cmap;
|
|
||||||
swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask |
|
|
||||||
ButtonPressMask;
|
|
||||||
win = XCreateWindow(dpy, parentwin, x, y, mw, mh, 0,
|
|
||||||
depth, InputOutput, visual,
|
|
||||||
CWOverrideRedirect | CWBackPixel | CWColormap | CWEventMask | CWBorderPixel, &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 [-bfiPrv] [-l lines] [-p prompt] [-fn font] [-m monitor]\n"
|
|
||||||
" [-nb color] [-nf color] [-sb color] [-sf color] [-w windowid]\n", stderr);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
read_Xresources(void) {
|
|
||||||
XrmInitialize();
|
|
||||||
|
|
||||||
char* xrm;
|
|
||||||
if ((xrm = XResourceManagerString(drw->dpy))) {
|
|
||||||
char *type;
|
|
||||||
XrmDatabase xdb = XrmGetStringDatabase(xrm);
|
|
||||||
XrmValue xval;
|
|
||||||
|
|
||||||
if (XrmGetResource(xdb, "dmenu.font", "*", &type, &xval) == True) /* font or font set */
|
|
||||||
fonts[0] = strdup(xval.addr);
|
|
||||||
if (XrmGetResource(xdb, "dmenu.color0", "*", &type, &xval) == True) /* normal background color */
|
|
||||||
colors[SchemeNorm][ColBg] = strdup(xval.addr);
|
|
||||||
if (XrmGetResource(xdb, "dmenu.color4", "*", &type, &xval) == True) /* normal foreground color */
|
|
||||||
colors[SchemeNorm][ColFg] = strdup(xval.addr);
|
|
||||||
if (XrmGetResource(xdb, "dmenu.color4", "*", &type, &xval) == True) /* selected background color */
|
|
||||||
colors[SchemeSel][ColBg] = strdup(xval.addr);
|
|
||||||
if (XrmGetResource(xdb, "dmenu.color0", "*", &type, &xval) == True) /* selected foreground color */
|
|
||||||
colors[SchemeSel][ColFg] = strdup(xval.addr);
|
|
||||||
|
|
||||||
XrmDestroyDatabase(xdb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 (!strcmp(argv[i], "-P")) /* is the input a password */
|
|
||||||
passwd = 1;
|
|
||||||
else if (!strcmp(argv[i], "-r")) /* reject input which results in no match */
|
|
||||||
reject_no_match = 1;
|
|
||||||
else if (i + 1 == argc)
|
|
||||||
usage();
|
|
||||||
/* these options take one argument */
|
|
||||||
else if (!strcmp(argv[i], "-l")) /* number of lines in vertical list */
|
|
||||||
lines = atoi(argv[++i]);
|
|
||||||
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);
|
|
||||||
read_Xresources();
|
|
||||||
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 */
|
|
||||||
}
|
|
Binary file not shown.
|
@ -1,13 +0,0 @@
|
||||||
#!/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
|
|
|
@ -1,2 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
dmenu_path | dmenu "$@" | ${SHELL:-"/bin/sh"} &
|
|
|
@ -1,424 +0,0 @@
|
||||||
/* 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 & 0x00FFFFFFFU) | 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);
|
|
||||||
}
|
|
|
@ -1,60 +0,0 @@
|
||||||
/* 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 *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);
|
|
Binary file not shown.
Binary file not shown.
|
@ -1,90 +0,0 @@
|
||||||
.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)
|
|
|
@ -1,109 +0,0 @@
|
||||||
/* 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 (n && 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;
|
|
||||||
}
|
|
Binary file not shown.
|
@ -1,35 +0,0 @@
|
||||||
/* 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);
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
/* 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);
|
|
Binary file not shown.
|
@ -1,2 +0,0 @@
|
||||||
custom: ["https://lukesmith.xyz/donate.html"]
|
|
||||||
github: lukesmithxyz
|
|
|
@ -1,38 +0,0 @@
|
||||||
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>
|
|
||||||
© 2019-2020 Luke Smith <luke@lukesmith.xyz>
|
|
||||||
|
|
||||||
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.
|
|
|
@ -1,52 +0,0 @@
|
||||||
# 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
|
|
||||||
|
|
||||||
dwm: ${OBJ}
|
|
||||||
${CC} -o $@ ${OBJ} ${LDFLAGS}
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -f dwm ${OBJ} dwm-${VERSION}.tar.gz *.orig *.rej
|
|
||||||
|
|
||||||
dist: clean
|
|
||||||
mkdir -p dwm-${VERSION}
|
|
||||||
cp -R LICENSE Makefile README config.mk\
|
|
||||||
dwm.1 drw.h util.h ${SRC} 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
|
|
||||||
# mkdir -p ${DESTDIR}${PREFIX}/share/dwm
|
|
||||||
# cp -f larbs.mom ${DESTDIR}${PREFIX}/share/dwm
|
|
||||||
# chmod 644 ${DESTDIR}${PREFIX}/share/dwm/larbs.mom
|
|
||||||
|
|
||||||
uninstall:
|
|
||||||
rm -f ${DESTDIR}${PREFIX}/bin/dwm\
|
|
||||||
# ${DESTDIR}${PREFIX}/share/dwm/larbs.mom\
|
|
||||||
${DESTDIR}${MANPREFIX}/man1/dwm.1
|
|
||||||
|
|
||||||
.PHONY: all options clean dist install uninstall
|
|
|
@ -1,46 +0,0 @@
|
||||||
_pkgname=dwm
|
|
||||||
pkgname=$_pkgname-larbs-git
|
|
||||||
pkgver=6.2.r1888.0ac09e0
|
|
||||||
pkgrel=1
|
|
||||||
pkgdesc="Luke's build of dwm"
|
|
||||||
url=https://github.com/LukeSmithxyz/dwm
|
|
||||||
arch=(i686 x86_64)
|
|
||||||
license=(MIT)
|
|
||||||
makedepends=(git)
|
|
||||||
depends=(freetype2 libx11 libxft)
|
|
||||||
optdepends=(
|
|
||||||
'libxft-bgra: if dwm crashes when displaying emojis'
|
|
||||||
'libxft-bgra-git: if dwm crashes when displaying emojis'
|
|
||||||
'dmenu: program launcher'
|
|
||||||
'st: terminal emulator')
|
|
||||||
provides=($_pkgname)
|
|
||||||
conflicts=($_pkgname)
|
|
||||||
source=(git+https://github.com/LukeSmithxyz/dwm)
|
|
||||||
sha256sums=('SKIP')
|
|
||||||
|
|
||||||
pkgver() {
|
|
||||||
cd "$_pkgname"
|
|
||||||
echo "$(awk '/^VERSION =/ {print $3}' config.mk)".r"$(git rev-list --count HEAD)"."$(git rev-parse --short HEAD)"
|
|
||||||
}
|
|
||||||
|
|
||||||
prepare() {
|
|
||||||
cd "$_pkgname"
|
|
||||||
echo "CPPFLAGS+=${CPPFLAGS}" >> config.mk
|
|
||||||
echo "CFLAGS+=${CFLAGS}" >> config.mk
|
|
||||||
echo "LDFLAGS+=${LDFLAGS}" >> config.mk
|
|
||||||
# to use a custom config.h, place it in the package directory
|
|
||||||
if [[ -f ${SRCDEST}/config.h ]]; then
|
|
||||||
cp "${SRCDEST}/config.h" .
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
build() {
|
|
||||||
cd "$_pkgname"
|
|
||||||
make X11INC=/usr/include/X11 X11LIB=/usr/lib/X11
|
|
||||||
}
|
|
||||||
|
|
||||||
package() {
|
|
||||||
cd "$_pkgname"
|
|
||||||
make PREFIX=/usr DESTDIR="$pkgdir" install
|
|
||||||
install -Dm644 LICENSE "$pkgdir/usr/share/licenses/$pkgname/LICENSE"
|
|
||||||
}
|
|
|
@ -1,39 +0,0 @@
|
||||||
# Luke's build of dwm
|
|
||||||
|
|
||||||
## FAQ
|
|
||||||
|
|
||||||
> What are the bindings?
|
|
||||||
|
|
||||||
This is suckless, mmmbud, the source code is the documentation! Check out [config.h](config.h).
|
|
||||||
|
|
||||||
Okay, okay, actually I keep a readme in `larbs.mom` for my whole system, including the binds here.
|
|
||||||
Press <kbd>super+F1</kbd> to view it in dwm (zathura is required for that binding).
|
|
||||||
I haven't kept `man dwm`/`dwm.1` updated though. PRs welcome on that, lol.
|
|
||||||
|
|
||||||
## Patches and features
|
|
||||||
|
|
||||||
- [Clickable statusbar](https://dwm.suckless.org/patches/statuscmd/) with my build of [dwmblocks](https://github.com/lukesmithxyz/dwmblocks).
|
|
||||||
- Reads [xresources](https://dwm.suckless.org/patches/xresources/) colors/variables (i.e. works with `pywal`, etc.).
|
|
||||||
- scratchpad: Accessible with <kbd>mod+shift+enter</kbd>.
|
|
||||||
- New layouts: bstack, fibonacci, deck, centered master and more. All bound to keys <kbd>super+(shift+)t/y/u/i</kbd>.
|
|
||||||
- True fullscreen (<kbd>super+f</kbd>) and prevents focus shifting.
|
|
||||||
- Windows can be made sticky (<kbd>super+s</kbd>).
|
|
||||||
- [stacker](https://dwm.suckless.org/patches/stacker/): Move windows up the stack manually (<kbd>super-K/J</kbd>).
|
|
||||||
- [shiftview](https://dwm.suckless.org/patches/nextprev/): Cycle through tags (<kbd>super+g/;</kbd>).
|
|
||||||
- [vanitygaps](https://dwm.suckless.org/patches/vanitygaps/): Gaps allowed across all layouts.
|
|
||||||
- [swallow patch](https://dwm.suckless.org/patches/swallow/): if a program run from a terminal would make it inoperable, it temporarily takes its place to save space.
|
|
||||||
|
|
||||||
|
|
||||||
## Installation for newbs
|
|
||||||
|
|
||||||
```bash
|
|
||||||
git clone https://github.com/LukeSmithxyz/dwm.git
|
|
||||||
cd dwm
|
|
||||||
sudo make install
|
|
||||||
```
|
|
||||||
|
|
||||||
There is also a `PKGBUILD` usable on distributions with pacman. Run `makepkg -si` instead of `sudo make install`.
|
|
||||||
|
|
||||||
### You must also install `libxft-bgra`!
|
|
||||||
|
|
||||||
This build of dwm does not block color emoji in the status/info bar, so you must install [libxft-bgra](https://aur.archlinux.org/packages/libxft-bgra/), which fixes a libxft color emoji rendering problem, otherwise dwm will crash upon trying to render one. Hopefully this fix will be in all libxft soon enough.
|
|
|
@ -1,65 +0,0 @@
|
||||||
[
|
|
||||||
{
|
|
||||||
"arguments": [
|
|
||||||
"/usr/bin/cc",
|
|
||||||
"-c",
|
|
||||||
"-std=c99",
|
|
||||||
"-pedantic",
|
|
||||||
"-Wall",
|
|
||||||
"-Wno-deprecated-declarations",
|
|
||||||
"-Os",
|
|
||||||
"-I/usr/X11R6/include",
|
|
||||||
"-I/usr/include/freetype2",
|
|
||||||
"-D_DEFAULT_SOURCE",
|
|
||||||
"-D_BSD_SOURCE",
|
|
||||||
"-D_POSIX_C_SOURCE=200809L",
|
|
||||||
"-DVERSION=\"6.2\"",
|
|
||||||
"-DXINERAMA",
|
|
||||||
"drw.c"
|
|
||||||
],
|
|
||||||
"directory": "/home/luca/.local/src/dwm",
|
|
||||||
"file": "/home/luca/.local/src/dwm/drw.c"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"arguments": [
|
|
||||||
"/usr/bin/cc",
|
|
||||||
"-c",
|
|
||||||
"-std=c99",
|
|
||||||
"-pedantic",
|
|
||||||
"-Wall",
|
|
||||||
"-Wno-deprecated-declarations",
|
|
||||||
"-Os",
|
|
||||||
"-I/usr/X11R6/include",
|
|
||||||
"-I/usr/include/freetype2",
|
|
||||||
"-D_DEFAULT_SOURCE",
|
|
||||||
"-D_BSD_SOURCE",
|
|
||||||
"-D_POSIX_C_SOURCE=200809L",
|
|
||||||
"-DVERSION=\"6.2\"",
|
|
||||||
"-DXINERAMA",
|
|
||||||
"dwm.c"
|
|
||||||
],
|
|
||||||
"directory": "/home/luca/.local/src/dwm",
|
|
||||||
"file": "/home/luca/.local/src/dwm/dwm.c"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"arguments": [
|
|
||||||
"/usr/bin/cc",
|
|
||||||
"-c",
|
|
||||||
"-std=c99",
|
|
||||||
"-pedantic",
|
|
||||||
"-Wall",
|
|
||||||
"-Wno-deprecated-declarations",
|
|
||||||
"-Os",
|
|
||||||
"-I/usr/X11R6/include",
|
|
||||||
"-I/usr/include/freetype2",
|
|
||||||
"-D_DEFAULT_SOURCE",
|
|
||||||
"-D_BSD_SOURCE",
|
|
||||||
"-D_POSIX_C_SOURCE=200809L",
|
|
||||||
"-DVERSION=\"6.2\"",
|
|
||||||
"-DXINERAMA",
|
|
||||||
"util.c"
|
|
||||||
],
|
|
||||||
"directory": "/home/luca/.local/src/dwm",
|
|
||||||
"file": "/home/luca/.local/src/dwm/util.c"
|
|
||||||
}
|
|
||||||
]
|
|
|
@ -1,542 +0,0 @@
|
||||||
/* See LICENSE file for copyright and license details. */
|
|
||||||
|
|
||||||
/* Constants */
|
|
||||||
#define TERMINAL "kitty"
|
|
||||||
#define TERMCLASS "kitty"
|
|
||||||
#define BROWSER "librewolf"
|
|
||||||
|
|
||||||
/* appearance */
|
|
||||||
static unsigned int borderpx = 2; /* border pixel of windows */
|
|
||||||
static unsigned int snap = 33; /* snap pixel */
|
|
||||||
static unsigned int gappih = 10; /* horiz inner gap between windows */
|
|
||||||
static unsigned int gappiv = 10; /* vert inner gap between windows */
|
|
||||||
static unsigned int gappoh =
|
|
||||||
10; /* horiz outer gap between windows and screen edge */
|
|
||||||
static unsigned int gappov =
|
|
||||||
10; /* vert outer gap between windows and screen edge */
|
|
||||||
static int swallowfloating =
|
|
||||||
0; /* 1 means swallow floating windows by default */
|
|
||||||
static int smartgaps =
|
|
||||||
0; /* 1 means no outer gap when there is only one window */
|
|
||||||
static int showbar = 1; /* 0 means no bar */
|
|
||||||
static int topbar = 1; /* 0 means bottom bar */
|
|
||||||
static char *fonts[] = {
|
|
||||||
"FiraCode Nerd Font Mono:size=10:antialias=true:autohint=true"};
|
|
||||||
static char normbgcolor[] = "#222222";
|
|
||||||
static char normbordercolor[] = "#444444";
|
|
||||||
static char normfgcolor[] = "#bbbbbb";
|
|
||||||
static char selfgcolor[] = "#eeeeee";
|
|
||||||
static char selbordercolor[] = "#770000";
|
|
||||||
static char selbgcolor[] = "#005577";
|
|
||||||
static char *colors[][3] = {
|
|
||||||
/* fg bg border */
|
|
||||||
[SchemeNorm] = {normfgcolor, normbgcolor, normbordercolor},
|
|
||||||
[SchemeSel] = {selfgcolor, selbgcolor, selbordercolor},
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
const char *name;
|
|
||||||
const void *cmd;
|
|
||||||
} Sp;
|
|
||||||
const char *spcmd1[] = {TERMINAL,
|
|
||||||
"--name",
|
|
||||||
"spterm",
|
|
||||||
"-o",
|
|
||||||
"initial_window_width=120c",
|
|
||||||
"-o",
|
|
||||||
"initial_window_height=34c",
|
|
||||||
"-o",
|
|
||||||
"remember_window_size=no",
|
|
||||||
"-o",
|
|
||||||
"background_opacity=0.8",
|
|
||||||
"-o",
|
|
||||||
"tab_bar_min_tabs=9001",
|
|
||||||
NULL};
|
|
||||||
const char *spcmd2[] = {TERMINAL,
|
|
||||||
"--name",
|
|
||||||
"spcalc",
|
|
||||||
"-o",
|
|
||||||
"remember_window_size=no",
|
|
||||||
"-o",
|
|
||||||
"font_size=16",
|
|
||||||
"-o",
|
|
||||||
"initial_window_width=50c",
|
|
||||||
"-o",
|
|
||||||
"initial_window_height=20c",
|
|
||||||
"-o",
|
|
||||||
"background_opacity=0.8",
|
|
||||||
"-o",
|
|
||||||
"confirm_os_window_close=0",
|
|
||||||
"-o",
|
|
||||||
"tab_bar_min_tabs=9001",
|
|
||||||
"-e",
|
|
||||||
"bc",
|
|
||||||
"-lq",
|
|
||||||
NULL};
|
|
||||||
static Sp scratchpads[] = {
|
|
||||||
/* name cmd */
|
|
||||||
{"spterm", spcmd1},
|
|
||||||
{"spcalc", spcmd2},
|
|
||||||
};
|
|
||||||
|
|
||||||
/* 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
|
|
||||||
isterminal noswallow monitor */
|
|
||||||
{"Gimp", NULL, NULL, 1 << 8, 0, 0, 0, -1},
|
|
||||||
{TERMCLASS, NULL, NULL, 0, 0, 1, 0, -1},
|
|
||||||
{NULL, NULL, "Event Tester", 0, 0, 0, 1, -1},
|
|
||||||
{NULL, "bg", NULL, 0, 0, 1, 1 << 7, -1},
|
|
||||||
{NULL, "spterm", NULL, SPTAG(0), 1, 1, 0, -1},
|
|
||||||
{NULL, "spcalc", NULL, SPTAG(1), 1, 1, 0, -1},
|
|
||||||
};
|
|
||||||
|
|
||||||
/* layout(s) */
|
|
||||||
static float mfact = 0.6; /* factor of master area size [0.05..0.95] */
|
|
||||||
static int nmaster = 1; /* number of clients in master area */
|
|
||||||
static int resizehints = 0; /* 1 means respect size hints in tiled resizals */
|
|
||||||
#define FORCE_VSPLIT \
|
|
||||||
1 /* nrowgrid layout: force two clients to always split vertically */
|
|
||||||
#include "vanitygaps.c"
|
|
||||||
static const Layout layouts[] = {
|
|
||||||
/* symbol arrange function */
|
|
||||||
{"[]=", tile}, /* Default: Master on left, slaves on right */
|
|
||||||
{"TTT", bstack}, /* Master on top, slaves on bottom */
|
|
||||||
|
|
||||||
{"[@]", spiral}, /* Fibonacci spiral */
|
|
||||||
{"[\\]", dwindle}, /* Decreasing in size right and leftward */
|
|
||||||
|
|
||||||
{"[D]", deck}, /* Master on left, slaves in monocle-like mode on right */
|
|
||||||
{"[M]", monocle}, /* All windows on top of eachother */
|
|
||||||
|
|
||||||
{"|M|", centeredmaster}, /* Master in middle, slaves on sides */
|
|
||||||
{">M>", centeredfloatingmaster}, /* Same but master floats */
|
|
||||||
|
|
||||||
{"><>", NULL}, /* no layout function means floating behavior */
|
|
||||||
{NULL, NULL},
|
|
||||||
};
|
|
||||||
|
|
||||||
/* key definitions */
|
|
||||||
#define MODKEY Mod4Mask
|
|
||||||
#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}},
|
|
||||||
#define STACKKEYS(MOD, ACTION) \
|
|
||||||
{MOD, XK_j, ACTION##stack, {.i = INC(+1)}}, \
|
|
||||||
{MOD, XK_k, ACTION##stack, {.i = INC(-1)}}, \
|
|
||||||
{MOD, \
|
|
||||||
XK_v, \
|
|
||||||
ACTION##stack, \
|
|
||||||
{.i = 0}}, /* { MOD, XK_grave, ACTION##stack, {.i = PREVSEL } }, \ */
|
|
||||||
/* { MOD, XK_a, ACTION##stack, {.i = 1 } }, \ */
|
|
||||||
/* { MOD, XK_z, ACTION##stack, {.i = 2 } }, \ */
|
|
||||||
/* { MOD, XK_x, ACTION##stack, {.i = -1 } }, */
|
|
||||||
|
|
||||||
/* 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 const char *termcmd[] = {TERMINAL,
|
|
||||||
"-o",
|
|
||||||
"background_opacity=0.8",
|
|
||||||
"-o",
|
|
||||||
"confirm_os_window_close=0",
|
|
||||||
"-o",
|
|
||||||
"tab_bar_min_tabs=9001",
|
|
||||||
NULL};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Xresources preferences to load at startup
|
|
||||||
*/
|
|
||||||
ResourcePref resources[] = {
|
|
||||||
{"color0", STRING, &normbordercolor},
|
|
||||||
{"color8", STRING, &selbordercolor},
|
|
||||||
{"color8", STRING, &normbgcolor},
|
|
||||||
{"color12", STRING, &normfgcolor},
|
|
||||||
{"color0", STRING, &selfgcolor},
|
|
||||||
{"color4", STRING, &selbgcolor},
|
|
||||||
{"borderpx", INTEGER, &borderpx},
|
|
||||||
{"snap", INTEGER, &snap},
|
|
||||||
{"showbar", INTEGER, &showbar},
|
|
||||||
{"topbar", INTEGER, &topbar},
|
|
||||||
{"nmaster", INTEGER, &nmaster},
|
|
||||||
{"resizehints", INTEGER, &resizehints},
|
|
||||||
{"mfact", FLOAT, &mfact},
|
|
||||||
{"gappih", INTEGER, &gappih},
|
|
||||||
{"gappiv", INTEGER, &gappiv},
|
|
||||||
{"gappoh", INTEGER, &gappoh},
|
|
||||||
{"gappov", INTEGER, &gappov},
|
|
||||||
{"swallowfloating", INTEGER, &swallowfloating},
|
|
||||||
{"smartgaps", INTEGER, &smartgaps},
|
|
||||||
};
|
|
||||||
|
|
||||||
#include "shiftview.c"
|
|
||||||
#include <X11/XF86keysym.h>
|
|
||||||
|
|
||||||
static Key keys[] = {
|
|
||||||
/* modifier key function argument */
|
|
||||||
STACKKEYS(MODKEY, focus) STACKKEYS(MODKEY | ShiftMask, push)
|
|
||||||
/* { MODKEY|ShiftMask, XK_Escape, spawn, SHCMD("") }, */
|
|
||||||
{MODKEY,
|
|
||||||
XK_dead_circumflex,
|
|
||||||
spawn,
|
|
||||||
{.v = (const char *[]){"dmenuunicode", NULL}}},
|
|
||||||
/* { MODKEY|ShiftMask, XK_grave, togglescratch,
|
|
||||||
* SHCMD("")
|
|
||||||
* },
|
|
||||||
*/
|
|
||||||
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, XK_0, view, {.ui = ~0}},
|
|
||||||
{MODKEY | ShiftMask, XK_0, tag, {.ui = ~0}},
|
|
||||||
{MODKEY, XK_ssharp, spawn,
|
|
||||||
SHCMD("pamixer --allow-boost -d 5; kill -44 $(pidof dwmblocks)")},
|
|
||||||
{MODKEY | ShiftMask, XK_ssharp, spawn,
|
|
||||||
SHCMD("pamixer --allow-boost -d 15; kill -44 $(pidof dwmblocks)")},
|
|
||||||
{MODKEY, XK_dead_acute, spawn,
|
|
||||||
SHCMD("pamixer --allow-boost -i 5; kill -44 $(pidof dwmblocks)")},
|
|
||||||
{MODKEY | ShiftMask, XK_dead_acute, spawn,
|
|
||||||
SHCMD("pamixer --allow-boost -i 15; kill -44 $(pidof dwmblocks)")},
|
|
||||||
{MODKEY, XK_BackSpace, spawn, {.v = (const char *[]){"sysact", NULL}}},
|
|
||||||
{MODKEY | ShiftMask,
|
|
||||||
XK_BackSpace,
|
|
||||||
spawn,
|
|
||||||
{.v = (const char *[]){"sysact", NULL}}},
|
|
||||||
|
|
||||||
{MODKEY, XK_Tab, view, {0}},
|
|
||||||
/* { MODKEY|ShiftMask, XK_Tab, spawn,
|
|
||||||
* SHCMD("")
|
|
||||||
* },
|
|
||||||
*/
|
|
||||||
{MODKEY, XK_q, killclient, {0}},
|
|
||||||
{MODKEY | ShiftMask, XK_q, spawn, {.v = (const char *[]){"sysact", NULL}}},
|
|
||||||
{MODKEY, XK_w, spawn, {.v = (const char *[]){BROWSER, NULL}}},
|
|
||||||
{MODKEY | ShiftMask,
|
|
||||||
XK_w,
|
|
||||||
spawn,
|
|
||||||
{.v = (const char *[]){TERMINAL, "-e", "sudo", "nmtui", NULL}}},
|
|
||||||
{MODKEY, XK_e, spawn,
|
|
||||||
SHCMD(
|
|
||||||
TERMINAL
|
|
||||||
" -e neomutt ; pkill -RTMIN+12 dwmblocks; rmdir ~/.abook")}, // REPLACE
|
|
||||||
{MODKEY | ShiftMask, XK_e, spawn,
|
|
||||||
SHCMD(TERMINAL " -e abook -C ~/.config/abook/abookrc --datafile "
|
|
||||||
"~/.config/abook/addressbook")}, // REPLACE
|
|
||||||
{MODKEY, XK_r, spawn, {.v = (const char *[]){TERMINAL, "-e", "lf", NULL}}},
|
|
||||||
{MODKEY | ShiftMask,
|
|
||||||
XK_r,
|
|
||||||
spawn,
|
|
||||||
{.v = (const char *[]){TERMINAL, "-e", "htop", NULL}}},
|
|
||||||
{MODKEY, XK_t, setlayout, {.v = &layouts[0]}}, /* tile */
|
|
||||||
{MODKEY | ShiftMask, XK_t, setlayout, {.v = &layouts[1]}}, /* bstack */
|
|
||||||
{MODKEY, XK_z, setlayout, {.v = &layouts[2]}}, /* spiral */
|
|
||||||
{MODKEY | ShiftMask, XK_z, setlayout, {.v = &layouts[3]}}, /* dwindle */
|
|
||||||
{MODKEY, XK_u, setlayout, {.v = &layouts[4]}}, /* deck */
|
|
||||||
{MODKEY | ShiftMask, XK_u, setlayout, {.v = &layouts[5]}}, /* monocle */
|
|
||||||
{MODKEY, XK_i, setlayout, {.v = &layouts[6]}}, /* centeredmaster */
|
|
||||||
{MODKEY | ShiftMask,
|
|
||||||
XK_i,
|
|
||||||
setlayout,
|
|
||||||
{.v = &layouts[7]}}, /* centeredfloatingmaster */
|
|
||||||
{MODKEY, XK_o, incnmaster, {.i = +1}},
|
|
||||||
{MODKEY | ShiftMask, XK_o, incnmaster, {.i = -1}},
|
|
||||||
{MODKEY, XK_p, spawn, {.v = (const char *[]){"mpc", "toggle", NULL}}},
|
|
||||||
{MODKEY | ShiftMask, XK_p, spawn, SHCMD("mpc pause ; pauseallmpv")},
|
|
||||||
{MODKEY,
|
|
||||||
XK_udiaeresis,
|
|
||||||
spawn,
|
|
||||||
{.v = (const char *[]){"mpc", "seek", "-10", NULL}}},
|
|
||||||
{MODKEY | ShiftMask,
|
|
||||||
XK_udiaeresis,
|
|
||||||
spawn,
|
|
||||||
{.v = (const char *[]){"mpc", "seek", "-60", NULL}}},
|
|
||||||
{MODKEY,
|
|
||||||
XK_plus,
|
|
||||||
spawn,
|
|
||||||
{.v = (const char *[]){"mpc", "seek", "+10", NULL}}},
|
|
||||||
{MODKEY | ShiftMask,
|
|
||||||
XK_plus,
|
|
||||||
spawn,
|
|
||||||
{.v = (const char *[]){"mpc", "seek", "+60", NULL}}},
|
|
||||||
{MODKEY,
|
|
||||||
XK_numbersign,
|
|
||||||
spawn,
|
|
||||||
{.v = (const char *[]){TERMINAL, "-e", "bc", "-l", NULL}}},
|
|
||||||
/* { MODKEY|ShiftMask, XK_backslash, spawn, SHCMD("")
|
|
||||||
* },
|
|
||||||
*/
|
|
||||||
|
|
||||||
{MODKEY, XK_a, togglegaps, {0}},
|
|
||||||
{MODKEY | ShiftMask, XK_a, defaultgaps, {0}},
|
|
||||||
{MODKEY, XK_s, togglesticky, {0}},
|
|
||||||
/* { MODKEY|ShiftMask, XK_s, spawn,
|
|
||||||
* SHCMD("")
|
|
||||||
* },
|
|
||||||
*/
|
|
||||||
{MODKEY, XK_d, spawn, {.v = (const char *[]){"dmenu_run", NULL}}},
|
|
||||||
{MODKEY | ShiftMask,
|
|
||||||
XK_d,
|
|
||||||
spawn,
|
|
||||||
{.v = (const char *[]){"passmenu", NULL}}},
|
|
||||||
{MODKEY, XK_f, togglefullscr, {0}},
|
|
||||||
{MODKEY | ShiftMask, XK_f, setlayout, {.v = &layouts[8]}},
|
|
||||||
{MODKEY, XK_g, shiftview, {.i = -1}},
|
|
||||||
{MODKEY | ShiftMask, XK_g, shifttag, {.i = -1}},
|
|
||||||
{MODKEY, XK_h, setmfact, {.f = -0.05}},
|
|
||||||
/* J and K are automatically bound above in STACKEYS */
|
|
||||||
{MODKEY, XK_l, setmfact, {.f = +0.05}},
|
|
||||||
{MODKEY, XK_odiaeresis, shiftview, {.i = 1}},
|
|
||||||
{MODKEY | ShiftMask, XK_odiaeresis, shifttag, {.i = 1}},
|
|
||||||
{MODKEY, XK_adiaeresis, togglescratch, {.ui = 1}},
|
|
||||||
/* { MODKEY|ShiftMask, XK_adiaeresis, spawn, SHCMD("")
|
|
||||||
* },
|
|
||||||
*/
|
|
||||||
{MODKEY | ShiftMask, XK_adiaeresis, togglesmartgaps, {0}},
|
|
||||||
{MODKEY, XK_Return, spawn, {.v = termcmd}},
|
|
||||||
{MODKEY | ShiftMask, XK_Return, togglescratch, {.ui = 0}},
|
|
||||||
|
|
||||||
{MODKEY, XK_y, incrgaps, {.i = +3}},
|
|
||||||
/* { MODKEY|ShiftMask, XK_y, spawn,
|
|
||||||
* SHCMD("")
|
|
||||||
* },
|
|
||||||
*/
|
|
||||||
{MODKEY, XK_x, incrgaps, {.i = -3}},
|
|
||||||
/* { MODKEY|ShiftMask, XK_x, spawn,
|
|
||||||
* SHCMD("")
|
|
||||||
* },
|
|
||||||
*/
|
|
||||||
/* { MODKEY, XK_c, spawn,
|
|
||||||
* SHCMD("")
|
|
||||||
* },
|
|
||||||
*/
|
|
||||||
/* { MODKEY|ShiftMask, XK_c, spawn,
|
|
||||||
* SHCMD("")
|
|
||||||
* },
|
|
||||||
*/
|
|
||||||
/* V is automatically bound above in STACKKEYS */
|
|
||||||
{MODKEY, XK_b, togglebar, {0}},
|
|
||||||
/* { MODKEY|ShiftMask, XK_b, spawn,
|
|
||||||
* SHCMD("")
|
|
||||||
* },
|
|
||||||
*/
|
|
||||||
{MODKEY,
|
|
||||||
XK_n,
|
|
||||||
spawn,
|
|
||||||
{.v = (const char *[]){TERMINAL, "-e", "nvim", "-c", "VimwikiIndex",
|
|
||||||
NULL}}},
|
|
||||||
{MODKEY | ShiftMask, XK_n, spawn,
|
|
||||||
SHCMD(TERMINAL " -e newsboat; pkill -RTMIN+6 dwmblocks")}, // TODO: replace
|
|
||||||
{MODKEY,
|
|
||||||
XK_m,
|
|
||||||
spawn,
|
|
||||||
{.v = (const char *[]){TERMINAL, "-e", "ncmpcpp", NULL}}},
|
|
||||||
{MODKEY | ShiftMask, XK_m, spawn,
|
|
||||||
SHCMD("pamixer -t; kill -44 $(pidof dwmblocks)")},
|
|
||||||
{MODKEY, XK_comma, spawn, {.v = (const char *[]){"mpc", "prev", NULL}}},
|
|
||||||
{MODKEY | ShiftMask,
|
|
||||||
XK_comma,
|
|
||||||
spawn,
|
|
||||||
{.v = (const char *[]){"mpc", "seek", "0%", NULL}}},
|
|
||||||
{MODKEY, XK_period, spawn, {.v = (const char *[]){"mpc", "next", NULL}}},
|
|
||||||
{MODKEY | ShiftMask,
|
|
||||||
XK_period,
|
|
||||||
spawn,
|
|
||||||
{.v = (const char *[]){"mpc", "repeat", NULL}}},
|
|
||||||
|
|
||||||
{MODKEY, XK_Left, focusmon, {.i = -1}},
|
|
||||||
{MODKEY | ShiftMask, XK_Left, tagmon, {.i = -1}},
|
|
||||||
{MODKEY, XK_Right, focusmon, {.i = +1}},
|
|
||||||
{MODKEY | ShiftMask, XK_Right, tagmon, {.i = +1}},
|
|
||||||
|
|
||||||
{MODKEY, XK_Page_Up, shiftview, {.i = -1}},
|
|
||||||
{MODKEY | ShiftMask, XK_Page_Up, shifttag, {.i = -1}},
|
|
||||||
{MODKEY, XK_Page_Down, shiftview, {.i = +1}},
|
|
||||||
{MODKEY | ShiftMask, XK_Page_Down, shifttag, {.i = +1}},
|
|
||||||
{MODKEY, XK_Insert, spawn,
|
|
||||||
SHCMD("xdotool type $(grep -v '^#' ~/.local/share/snippets | dmenu -i -l "
|
|
||||||
"50 | cut -d' ' -f1)")},
|
|
||||||
|
|
||||||
{MODKEY, XK_F1, spawn,
|
|
||||||
SHCMD("groff -mom /usr/local/share/dwm/keybinds.mom -Tpdf | zathura -")},
|
|
||||||
{MODKEY, XK_F2, spawn, SHCMD("$TERMINAL -e deluge-gtk")},
|
|
||||||
{MODKEY, XK_F3, spawn, SHCMD("librewolf")}, // TODO: replace
|
|
||||||
{MODKEY, XK_F4, spawn,
|
|
||||||
SHCMD(TERMINAL " -e pulsemixer; kill -44 $(pidof dwmblocks)")},
|
|
||||||
{MODKEY, XK_F5, spawn, SHCMD("")},
|
|
||||||
{MODKEY, XK_F6, spawn, SHCMD("")},
|
|
||||||
{MODKEY, XK_F7, spawn, SHCMD("")},
|
|
||||||
{MODKEY, XK_F8, spawn, SHCMD("")},
|
|
||||||
{MODKEY, XK_F9, spawn, SHCMD("")},
|
|
||||||
{MODKEY, XK_F10, spawn, {.v = (const char *[]){"dmenumount", NULL}}},
|
|
||||||
{MODKEY, XK_F11, spawn, {.v = (const char *[]){"dmenuumount", NULL}}},
|
|
||||||
{MODKEY, XK_F12, spawn,
|
|
||||||
SHCMD("remaps & notify-send \"⌨️ Keyboard remapping...\" \"Re-running "
|
|
||||||
"keyboard defaults for any newly plugged-in keyboards.\"")},
|
|
||||||
{MODKEY, XK_space, zoom, {0}},
|
|
||||||
{MODKEY | ShiftMask, XK_space, togglefloating, {0}},
|
|
||||||
|
|
||||||
{0, XK_Print, spawn, SHCMD("maim pic-full-$(date '+%y%m%d-%H%M-%S').png")},
|
|
||||||
{ShiftMask, XK_Print, spawn, {.v = (const char *[]){"maimpick", NULL}}},
|
|
||||||
{MODKEY, XK_Print, spawn, {.v = (const char *[]){"dmenurecord", NULL}}},
|
|
||||||
{MODKEY | ShiftMask,
|
|
||||||
XK_Print,
|
|
||||||
spawn,
|
|
||||||
{.v = (const char *[]){"dmenurecord", "kill", NULL}}},
|
|
||||||
{MODKEY,
|
|
||||||
XK_Delete,
|
|
||||||
spawn,
|
|
||||||
{.v = (const char *[]){"dmenurecord", "kill", NULL}}},
|
|
||||||
{MODKEY, XK_Scroll_Lock, spawn, SHCMD("killall screenkey || screenkey &")},
|
|
||||||
|
|
||||||
{0, XF86XK_AudioMute, spawn,
|
|
||||||
SHCMD("pamixer -t; kill -44 $(pidof dwmblocks)")},
|
|
||||||
{0, XF86XK_AudioRaiseVolume, spawn,
|
|
||||||
SHCMD("pamixer --allow-boost -i 3; kill -44 $(pidof dwmblocks)")},
|
|
||||||
{0, XF86XK_AudioLowerVolume, spawn,
|
|
||||||
SHCMD("pamixer --allow-boost -d 3; kill -44 $(pidof dwmblocks)")},
|
|
||||||
{0, XF86XK_AudioPrev, spawn, {.v = (const char *[]){"mpc", "prev", NULL}}},
|
|
||||||
{0, XF86XK_AudioNext, spawn, {.v = (const char *[]){"mpc", "next", NULL}}},
|
|
||||||
{0,
|
|
||||||
XF86XK_AudioPause,
|
|
||||||
spawn,
|
|
||||||
{.v = (const char *[]){"mpc", "pause", NULL}}},
|
|
||||||
{0, XF86XK_AudioPlay, spawn, {.v = (const char *[]){"mpc", "play", NULL}}},
|
|
||||||
{0, XF86XK_AudioStop, spawn, {.v = (const char *[]){"mpc", "stop", NULL}}},
|
|
||||||
{0,
|
|
||||||
XF86XK_AudioRewind,
|
|
||||||
spawn,
|
|
||||||
{.v = (const char *[]){"mpc", "seek", "-10", NULL}}},
|
|
||||||
{0,
|
|
||||||
XF86XK_AudioForward,
|
|
||||||
spawn,
|
|
||||||
{.v = (const char *[]){"mpc", "seek", "+10", NULL}}},
|
|
||||||
{0,
|
|
||||||
XF86XK_AudioMedia,
|
|
||||||
spawn,
|
|
||||||
{.v = (const char *[]){TERMINAL, "-e", "ncmpcpp", NULL}}},
|
|
||||||
{0, XF86XK_AudioMicMute, spawn,
|
|
||||||
SHCMD("pactl set-source-mute @DEFAULT_SOURCE@ toggle")},
|
|
||||||
{0, XF86XK_PowerOff, spawn, {.v = (const char *[]){"sysact", NULL}}},
|
|
||||||
{0,
|
|
||||||
XF86XK_Calculator,
|
|
||||||
spawn,
|
|
||||||
{.v = (const char *[]){TERMINAL, "-e", "bc", "-l", NULL}}},
|
|
||||||
{0,
|
|
||||||
XF86XK_Sleep,
|
|
||||||
spawn,
|
|
||||||
{.v = (const char *[]){"sudo", "-A", "zzz", NULL}}},
|
|
||||||
{0, XF86XK_WWW, spawn, {.v = (const char *[]){BROWSER, NULL}}},
|
|
||||||
{0, XF86XK_DOS, spawn, {.v = termcmd}},
|
|
||||||
{0, XF86XK_ScreenSaver, spawn,
|
|
||||||
SHCMD("slock & xset dpms force off; mpc pause; pauseallmpv")},
|
|
||||||
{0,
|
|
||||||
XF86XK_TaskPane,
|
|
||||||
spawn,
|
|
||||||
{.v = (const char *[]){TERMINAL, "-e", "htop", NULL}}},
|
|
||||||
{0, XF86XK_Mail, spawn,
|
|
||||||
SHCMD(TERMINAL " -e neomutt ; pkill -RTMIN+12 dwmblocks")},
|
|
||||||
{0,
|
|
||||||
XF86XK_MyComputer,
|
|
||||||
spawn,
|
|
||||||
{.v = (const char *[]){TERMINAL, "-e", "lfub", "/", NULL}}},
|
|
||||||
/* { 0, XF86XK_Battery, spawn,
|
|
||||||
* SHCMD("")
|
|
||||||
* },
|
|
||||||
*/
|
|
||||||
{0,
|
|
||||||
XF86XK_Launch1,
|
|
||||||
spawn,
|
|
||||||
{.v = (const char *[]){"xset", "dpms", "force", "off", NULL}}},
|
|
||||||
{0, XF86XK_TouchpadToggle, spawn,
|
|
||||||
SHCMD("(synclient | grep 'TouchpadOff.*1' && synclient TouchpadOff=0) || "
|
|
||||||
"synclient TouchpadOff=1")},
|
|
||||||
{0,
|
|
||||||
XF86XK_TouchpadOff,
|
|
||||||
spawn,
|
|
||||||
{.v = (const char *[]){"synclient", "TouchpadOff=1", NULL}}},
|
|
||||||
{0,
|
|
||||||
XF86XK_TouchpadOn,
|
|
||||||
spawn,
|
|
||||||
{.v = (const char *[]){"synclient", "TouchpadOff=0", NULL}}},
|
|
||||||
{0,
|
|
||||||
XF86XK_MonBrightnessUp,
|
|
||||||
spawn,
|
|
||||||
{.v = (const char *[]){"xbacklight", "-inc", "15", NULL}}},
|
|
||||||
{0,
|
|
||||||
XF86XK_MonBrightnessDown,
|
|
||||||
spawn,
|
|
||||||
{.v = (const char *[]){"xbacklight", "-dec", "15", NULL}}},
|
|
||||||
|
|
||||||
/* { MODKEY|Mod4Mask, XK_h, incrgaps, {.i = +1 } },
|
|
||||||
*/
|
|
||||||
/* { MODKEY|Mod4Mask, XK_l, incrgaps, {.i = -1 } },
|
|
||||||
*/
|
|
||||||
/* { MODKEY|Mod4Mask|ShiftMask, XK_h, incrogaps, {.i = +1 } },
|
|
||||||
*/
|
|
||||||
/* { MODKEY|Mod4Mask|ShiftMask, XK_l, incrogaps, {.i = -1 } },
|
|
||||||
*/
|
|
||||||
/* { MODKEY|Mod4Mask|ControlMask, XK_h, incrigaps, {.i = +1 } },
|
|
||||||
*/
|
|
||||||
/* { MODKEY|Mod4Mask|ControlMask, XK_l, incrigaps, {.i = -1 } },
|
|
||||||
*/
|
|
||||||
/* { MODKEY|Mod4Mask|ShiftMask, XK_0, defaultgaps, {0} }, */
|
|
||||||
/* { MODKEY, XK_y, incrihgaps, {.i = +1 } },
|
|
||||||
*/
|
|
||||||
/* { MODKEY, XK_o, incrihgaps, {.i = -1 } },
|
|
||||||
*/
|
|
||||||
/* { MODKEY|ControlMask, XK_y, incrivgaps, {.i = +1 } },
|
|
||||||
*/
|
|
||||||
/* { MODKEY|ControlMask, XK_o, incrivgaps, {.i = -1 } },
|
|
||||||
*/
|
|
||||||
/* { MODKEY|Mod4Mask, XK_y, incrohgaps, {.i = +1 } },
|
|
||||||
*/
|
|
||||||
/* { MODKEY|Mod4Mask, XK_o, incrohgaps, {.i = -1 } },
|
|
||||||
*/
|
|
||||||
/* { MODKEY|ShiftMask, XK_y, incrovgaps, {.i = +1 } },
|
|
||||||
*/
|
|
||||||
/* { MODKEY|ShiftMask, XK_o, incrovgaps, {.i = -1 } },
|
|
||||||
*/
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
/* button definitions */
|
|
||||||
/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle,
|
|
||||||
* ClkClientWin, or ClkRootWin */
|
|
||||||
static Button buttons[] = {
|
|
||||||
/* click event mask button function argument
|
|
||||||
*/
|
|
||||||
#ifndef __OpenBSD__
|
|
||||||
{ClkWinTitle, 0, Button2, zoom, {0}},
|
|
||||||
{ClkStatusText, 0, Button1, sigdwmblocks, {.i = 1}},
|
|
||||||
{ClkStatusText, 0, Button2, sigdwmblocks, {.i = 2}},
|
|
||||||
{ClkStatusText, 0, Button3, sigdwmblocks, {.i = 3}},
|
|
||||||
{ClkStatusText, 0, Button4, sigdwmblocks, {.i = 4}},
|
|
||||||
{ClkStatusText, 0, Button5, sigdwmblocks, {.i = 5}},
|
|
||||||
{ClkStatusText, ShiftMask, Button1, sigdwmblocks, {.i = 6}},
|
|
||||||
#endif
|
|
||||||
{ClkStatusText, ShiftMask, Button3, spawn,
|
|
||||||
SHCMD(TERMINAL " -e nvim ~/.local/src/dwmblocks/config.h")},
|
|
||||||
{ClkClientWin, MODKEY, Button1, movemouse, {0}},
|
|
||||||
{ClkClientWin, MODKEY, Button2, defaultgaps, {0}},
|
|
||||||
{ClkClientWin, MODKEY, Button3, resizemouse, {0}},
|
|
||||||
{ClkClientWin, MODKEY, Button4, incrgaps, {.i = +1}},
|
|
||||||
{ClkClientWin, MODKEY, Button5, incrgaps, {.i = -1}},
|
|
||||||
{ClkTagBar, 0, Button1, view, {0}},
|
|
||||||
{ClkTagBar, 0, Button3, toggleview, {0}},
|
|
||||||
{ClkTagBar, MODKEY, Button1, tag, {0}},
|
|
||||||
{ClkTagBar, MODKEY, Button3, toggletag, {0}},
|
|
||||||
{ClkTagBar, 0, Button4, shiftview, {.i = -1}},
|
|
||||||
{ClkTagBar, 0, Button5, shiftview, {.i = 1}},
|
|
||||||
{ClkRootWin, 0, Button2, togglebar, {0}},
|
|
||||||
};
|
|
|
@ -1,38 +0,0 @@
|
||||||
# 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} -lX11-xcb -lxcb -lxcb-res
|
|
||||||
|
|
||||||
# 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
|
|
|
@ -1,424 +0,0 @@
|
||||||
/* 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);
|
|
||||||
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, 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);
|
|
||||||
|
|
||||||
dest->pixel |= 0xff << 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, 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);
|
|
||||||
}
|
|
|
@ -1,57 +0,0 @@
|
||||||
/* 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;
|
|
||||||
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);
|
|
||||||
void drw_resize(Drw *drw, unsigned int w, unsigned int h);
|
|
||||||
void drw_free(Drw *drw);
|
|
||||||
|
|
||||||
/* Fnt abstraction */
|
|
||||||
Fnt *drw_fontset_create(Drw* drw, 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);
|
|
||||||
Clr *drw_scm_create(Drw *drw, char *clrnames[], 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);
|
|
Binary file not shown.
Binary file not shown.
|
@ -1,214 +0,0 @@
|
||||||
.TH DWM 1 dwm\-VERSION
|
|
||||||
.SH NAME
|
|
||||||
dwm \- dynamic window manager (Luke Smith <https://lukesmith.xyz>'s build)
|
|
||||||
.SH SYNOPSIS
|
|
||||||
.B dwm
|
|
||||||
.RB [ \-v ]
|
|
||||||
.SH DESCRIPTION
|
|
||||||
dwm is a dynamic window manager for X.
|
|
||||||
.P
|
|
||||||
dwm "orders" windows based on recency and primacy, while dwm layouts may
|
|
||||||
change, the most recent "master" window is shown in the most prominent
|
|
||||||
position. There are bindings for cycling through and promoting windows to the
|
|
||||||
master position.
|
|
||||||
.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.
|
|
||||||
.P
|
|
||||||
.I
|
|
||||||
libxft-bgra
|
|
||||||
should be installed for this build of dwm. Arch users may install it via the
|
|
||||||
AUR. Color characters and emoji are enabled, but these will cause crashes
|
|
||||||
without the fix
|
|
||||||
.I
|
|
||||||
libxft-bgra
|
|
||||||
offers.
|
|
||||||
.SH OPTIONS
|
|
||||||
.TP
|
|
||||||
.B \-v
|
|
||||||
prints version information to standard output, 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 Left click
|
|
||||||
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 Right click
|
|
||||||
click on a tag label adds/removes all windows with that tag to/from the view.
|
|
||||||
.TP
|
|
||||||
.B Super\-Left click
|
|
||||||
click on a tag label applies that tag to the focused window.
|
|
||||||
.TP
|
|
||||||
.B Super\-Right click
|
|
||||||
click on a tag label adds/removes that tag to/from the focused window.
|
|
||||||
.SS Keyboard commands
|
|
||||||
.TP
|
|
||||||
.B Super\-Return
|
|
||||||
Start terminal,
|
|
||||||
.BR st(1).
|
|
||||||
.TP
|
|
||||||
.B Super\-d
|
|
||||||
Spawn
|
|
||||||
.BR dmenu(1)
|
|
||||||
for launching other programs.
|
|
||||||
.TP
|
|
||||||
.B Super\-b
|
|
||||||
Toggles bar on and off.
|
|
||||||
.TP
|
|
||||||
.B Super\-q
|
|
||||||
Close focused window.
|
|
||||||
.TP
|
|
||||||
.B Super\-t/T
|
|
||||||
Sets tiled/bstack layouts.
|
|
||||||
.TP
|
|
||||||
.B Super\-f
|
|
||||||
Toggle fullscreen window.
|
|
||||||
.TP
|
|
||||||
.B Super\-F
|
|
||||||
Toggle floating layout.
|
|
||||||
.TP
|
|
||||||
.B Super\-y/Y
|
|
||||||
Sets Fibonacci spiral/dwinde layouts.
|
|
||||||
.TP
|
|
||||||
.B Super\-u/U
|
|
||||||
Sets centered master layout.
|
|
||||||
.TP
|
|
||||||
.B Super\-i/I
|
|
||||||
Sets centered master or floating master layouts.
|
|
||||||
.TP
|
|
||||||
.B Super\-space
|
|
||||||
Zooms/cycles focused window to/from master area.
|
|
||||||
.TP
|
|
||||||
.B Super\-j/k
|
|
||||||
Focus next/previous window.
|
|
||||||
.TP
|
|
||||||
.B Super\-Shift\-j/k
|
|
||||||
Move selected window down/up in stack.
|
|
||||||
.TP
|
|
||||||
.B Super\-o/O
|
|
||||||
Increase/decrease number of windows in master area.
|
|
||||||
.TP
|
|
||||||
.B Super\-l
|
|
||||||
Increase master area size.
|
|
||||||
.TP
|
|
||||||
.B Super\-h
|
|
||||||
Decrease master area size.
|
|
||||||
.TP
|
|
||||||
.B Super\-Shift\-space
|
|
||||||
Toggle focused window between tiled and floating state.
|
|
||||||
.TP
|
|
||||||
.B Super\-Tab
|
|
||||||
Toggles to the previously selected tags.
|
|
||||||
.TP
|
|
||||||
.B Super\-g
|
|
||||||
Moves to the previous tag.
|
|
||||||
.TP
|
|
||||||
.B Super\-Shift\-g
|
|
||||||
Moves selected window to the previous tag.
|
|
||||||
.TP
|
|
||||||
.B Super\-;
|
|
||||||
Moves to the next tag.
|
|
||||||
.TP
|
|
||||||
.B Super\-Shift\-;
|
|
||||||
Moves selected window to the next tag.
|
|
||||||
.TP
|
|
||||||
.B Super\-PageUp
|
|
||||||
Moves to the previous tag.
|
|
||||||
.TP
|
|
||||||
.B Super\-Shift\-PageUp
|
|
||||||
Moves selected window to the previous tag.
|
|
||||||
.TP
|
|
||||||
.B Super\-Pagedown
|
|
||||||
Moves to the next tag.
|
|
||||||
.TP
|
|
||||||
.B Super\-Shift\-PageDown
|
|
||||||
Moves selected window to the next tag.
|
|
||||||
.TP
|
|
||||||
.B Super\-a
|
|
||||||
Toggle gaps.
|
|
||||||
.TP
|
|
||||||
.B Super\-z
|
|
||||||
Increase gaps between windows.
|
|
||||||
.TP
|
|
||||||
.B Super\-x
|
|
||||||
Decrease gaps between windows.
|
|
||||||
.TP
|
|
||||||
.B Super\-Shift\-[1..n]
|
|
||||||
Apply nth tag to focused window.
|
|
||||||
.TP
|
|
||||||
.B Super\-Shift\-0
|
|
||||||
Apply all tags to focused window.
|
|
||||||
.TP
|
|
||||||
.B Super\-Control\-Shift\-[1..n]
|
|
||||||
Add/remove nth tag to/from focused window.
|
|
||||||
.TP
|
|
||||||
.B Super\-[1..n]
|
|
||||||
View all windows with nth tag.
|
|
||||||
.TP
|
|
||||||
.B Super\-0
|
|
||||||
View all windows with any tag.
|
|
||||||
.TP
|
|
||||||
.B Super\-Control\-[1..n]
|
|
||||||
Add/remove all windows with nth tag to/from the view.
|
|
||||||
.TP
|
|
||||||
.B Super\-Shift\-q
|
|
||||||
Quit dwm.
|
|
||||||
.TP
|
|
||||||
.B Mod1\-Control\-Shift\-q
|
|
||||||
Menu to refresh/quit/reboot/shutdown.
|
|
||||||
.SS Mouse commands
|
|
||||||
.TP
|
|
||||||
.B Super\-Left click
|
|
||||||
Move focused window while dragging. Tiled windows will be toggled to the floating state.
|
|
||||||
.TP
|
|
||||||
.B Super\-Middle click
|
|
||||||
Toggles focused window between floating and tiled state.
|
|
||||||
.TP
|
|
||||||
.B Super\-Right click
|
|
||||||
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 SIGNALS
|
|
||||||
.TP
|
|
||||||
.B SIGHUP - 1
|
|
||||||
Restart the dwm process.
|
|
||||||
.TP
|
|
||||||
.B SIGTERM - 15
|
|
||||||
Cleanly terminate the dwm process.
|
|
||||||
.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.
|
|
File diff suppressed because it is too large
Load diff
Binary file not shown.
|
@ -1,64 +0,0 @@
|
||||||
/** 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;
|
|
||||||
Client *c;
|
|
||||||
unsigned int tagmask = 0;
|
|
||||||
|
|
||||||
for (c = selmon->clients; c; c = c->next)
|
|
||||||
if (!(c->tags & SPTAGMASK))
|
|
||||||
tagmask = tagmask | c->tags;
|
|
||||||
|
|
||||||
shifted.ui = selmon->tagset[selmon->seltags] & ~SPTAGMASK;
|
|
||||||
if (arg->i > 0) /* left circular shift */
|
|
||||||
do {
|
|
||||||
shifted.ui = (shifted.ui << arg->i)
|
|
||||||
| (shifted.ui >> (LENGTH(tags) - arg->i));
|
|
||||||
shifted.ui &= ~SPTAGMASK;
|
|
||||||
} while (tagmask && !(shifted.ui & tagmask));
|
|
||||||
else /* right circular shift */
|
|
||||||
do {
|
|
||||||
shifted.ui = (shifted.ui >> (- arg->i)
|
|
||||||
| shifted.ui << (LENGTH(tags) + arg->i));
|
|
||||||
shifted.ui &= ~SPTAGMASK;
|
|
||||||
} while (tagmask && !(shifted.ui & tagmask));
|
|
||||||
|
|
||||||
view(&shifted);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
shifttag(const Arg *arg)
|
|
||||||
{
|
|
||||||
Arg a;
|
|
||||||
Client *c;
|
|
||||||
unsigned visible = 0;
|
|
||||||
int i = arg->i;
|
|
||||||
int count = 0;
|
|
||||||
int nextseltags, curseltags = selmon->tagset[selmon->seltags];
|
|
||||||
|
|
||||||
do {
|
|
||||||
if(i > 0) // left circular shift
|
|
||||||
nextseltags = (curseltags << i) | (curseltags >> (LENGTH(tags) - i));
|
|
||||||
|
|
||||||
else // right circular shift
|
|
||||||
nextseltags = curseltags >> (- i) | (curseltags << (LENGTH(tags) + i));
|
|
||||||
|
|
||||||
// Check if tag is visible
|
|
||||||
for (c = selmon->clients; c && !visible; c = c->next)
|
|
||||||
if (nextseltags & c->tags) {
|
|
||||||
visible = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
i += arg->i;
|
|
||||||
} while (!visible && ++count < 10);
|
|
||||||
|
|
||||||
if (count < 10) {
|
|
||||||
a.i = nextseltags;
|
|
||||||
tag(&a);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,42 +0,0 @@
|
||||||
/* 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);
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
/* 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);
|
|
||||||
}
|
|
|
@ -1,8 +0,0 @@
|
||||||
/* 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);
|
|
Binary file not shown.
|
@ -1,550 +0,0 @@
|
||||||
/* Key binding functions */
|
|
||||||
static void defaultgaps(const Arg *arg);
|
|
||||||
static void incrgaps(const Arg *arg);
|
|
||||||
/* static void incrigaps(const Arg *arg); */
|
|
||||||
/* static void incrogaps(const Arg *arg); */
|
|
||||||
/* static void incrohgaps(const Arg *arg); */
|
|
||||||
/* static void incrovgaps(const Arg *arg); */
|
|
||||||
/* static void incrihgaps(const Arg *arg); */
|
|
||||||
/* static void incrivgaps(const Arg *arg); */
|
|
||||||
static void togglegaps(const Arg *arg);
|
|
||||||
static void togglesmartgaps(const Arg *arg);
|
|
||||||
|
|
||||||
/* Layouts */
|
|
||||||
static void bstack(Monitor *m);
|
|
||||||
static void centeredmaster(Monitor *m);
|
|
||||||
static void centeredfloatingmaster(Monitor *m);
|
|
||||||
static void deck(Monitor *m);
|
|
||||||
static void dwindle(Monitor *m);
|
|
||||||
static void fibonacci(Monitor *m, int s);
|
|
||||||
static void spiral(Monitor *m);
|
|
||||||
static void tile(Monitor *);
|
|
||||||
|
|
||||||
/* Internals */
|
|
||||||
static void getgaps(Monitor *m, int *oh, int *ov, int *ih, int *iv, unsigned int *nc);
|
|
||||||
static void setgaps(int oh, int ov, int ih, int iv);
|
|
||||||
|
|
||||||
/* Settings */
|
|
||||||
static int enablegaps = 1;
|
|
||||||
|
|
||||||
static void
|
|
||||||
setgaps(int oh, int ov, int ih, int iv)
|
|
||||||
{
|
|
||||||
if (oh < 0) oh = 0;
|
|
||||||
if (ov < 0) ov = 0;
|
|
||||||
if (ih < 0) ih = 0;
|
|
||||||
if (iv < 0) iv = 0;
|
|
||||||
|
|
||||||
selmon->gappoh = oh;
|
|
||||||
selmon->gappov = ov;
|
|
||||||
selmon->gappih = ih;
|
|
||||||
selmon->gappiv = iv;
|
|
||||||
arrange(selmon);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
togglegaps(const Arg *arg)
|
|
||||||
{
|
|
||||||
enablegaps = !enablegaps;
|
|
||||||
arrange(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
togglesmartgaps(const Arg *arg)
|
|
||||||
{
|
|
||||||
smartgaps = !smartgaps;
|
|
||||||
arrange(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
defaultgaps(const Arg *arg)
|
|
||||||
{
|
|
||||||
setgaps(gappoh, gappov, gappih, gappiv);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
incrgaps(const Arg *arg)
|
|
||||||
{
|
|
||||||
setgaps(
|
|
||||||
selmon->gappoh + arg->i,
|
|
||||||
selmon->gappov + arg->i,
|
|
||||||
selmon->gappih + arg->i,
|
|
||||||
selmon->gappiv + arg->i
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* static void */
|
|
||||||
/* incrigaps(const Arg *arg) */
|
|
||||||
/* { */
|
|
||||||
/* setgaps( */
|
|
||||||
/* selmon->gappoh, */
|
|
||||||
/* selmon->gappov, */
|
|
||||||
/* selmon->gappih + arg->i, */
|
|
||||||
/* selmon->gappiv + arg->i */
|
|
||||||
/* ); */
|
|
||||||
/* } */
|
|
||||||
|
|
||||||
/* static void */
|
|
||||||
/* incrogaps(const Arg *arg) */
|
|
||||||
/* { */
|
|
||||||
/* setgaps( */
|
|
||||||
/* selmon->gappoh + arg->i, */
|
|
||||||
/* selmon->gappov + arg->i, */
|
|
||||||
/* selmon->gappih, */
|
|
||||||
/* selmon->gappiv */
|
|
||||||
/* ); */
|
|
||||||
/* } */
|
|
||||||
|
|
||||||
/* static void */
|
|
||||||
/* incrohgaps(const Arg *arg) */
|
|
||||||
/* { */
|
|
||||||
/* setgaps( */
|
|
||||||
/* selmon->gappoh + arg->i, */
|
|
||||||
/* selmon->gappov, */
|
|
||||||
/* selmon->gappih, */
|
|
||||||
/* selmon->gappiv */
|
|
||||||
/* ); */
|
|
||||||
/* } */
|
|
||||||
|
|
||||||
/* static void */
|
|
||||||
/* incrovgaps(const Arg *arg) */
|
|
||||||
/* { */
|
|
||||||
/* setgaps( */
|
|
||||||
/* selmon->gappoh, */
|
|
||||||
/* selmon->gappov + arg->i, */
|
|
||||||
/* selmon->gappih, */
|
|
||||||
/* selmon->gappiv */
|
|
||||||
/* ); */
|
|
||||||
/* } */
|
|
||||||
|
|
||||||
/* static void */
|
|
||||||
/* incrihgaps(const Arg *arg) */
|
|
||||||
/* { */
|
|
||||||
/* setgaps( */
|
|
||||||
/* selmon->gappoh, */
|
|
||||||
/* selmon->gappov, */
|
|
||||||
/* selmon->gappih + arg->i, */
|
|
||||||
/* selmon->gappiv */
|
|
||||||
/* ); */
|
|
||||||
/* } */
|
|
||||||
|
|
||||||
/* static void */
|
|
||||||
/* incrivgaps(const Arg *arg) */
|
|
||||||
/* { */
|
|
||||||
/* setgaps( */
|
|
||||||
/* selmon->gappoh, */
|
|
||||||
/* selmon->gappov, */
|
|
||||||
/* selmon->gappih, */
|
|
||||||
/* selmon->gappiv + arg->i */
|
|
||||||
/* ); */
|
|
||||||
/* } */
|
|
||||||
|
|
||||||
static void
|
|
||||||
getgaps(Monitor *m, int *oh, int *ov, int *ih, int *iv, unsigned int *nc)
|
|
||||||
{
|
|
||||||
unsigned int n, oe, ie;
|
|
||||||
oe = ie = enablegaps;
|
|
||||||
Client *c;
|
|
||||||
|
|
||||||
for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
|
|
||||||
if (smartgaps && n == 1) {
|
|
||||||
oe = 0; // outer gaps disabled when only one client
|
|
||||||
}
|
|
||||||
|
|
||||||
*oh = m->gappoh*oe; // outer horizontal gap
|
|
||||||
*ov = m->gappov*oe; // outer vertical gap
|
|
||||||
*ih = m->gappih*ie; // inner horizontal gap
|
|
||||||
*iv = m->gappiv*ie; // inner vertical gap
|
|
||||||
*nc = n; // number of clients
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
getfacts(Monitor *m, int msize, int ssize, float *mf, float *sf, int *mr, int *sr)
|
|
||||||
{
|
|
||||||
unsigned int n;
|
|
||||||
float mfacts, sfacts;
|
|
||||||
int mtotal = 0, stotal = 0;
|
|
||||||
Client *c;
|
|
||||||
|
|
||||||
for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++);
|
|
||||||
mfacts = MIN(n, m->nmaster);
|
|
||||||
sfacts = n - m->nmaster;
|
|
||||||
|
|
||||||
for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++)
|
|
||||||
if (n < m->nmaster)
|
|
||||||
mtotal += msize / mfacts;
|
|
||||||
else
|
|
||||||
stotal += ssize / sfacts;
|
|
||||||
|
|
||||||
*mf = mfacts; // total factor of master area
|
|
||||||
*sf = sfacts; // total factor of stack area
|
|
||||||
*mr = msize - mtotal; // the remainder (rest) of pixels after an even master split
|
|
||||||
*sr = ssize - stotal; // the remainder (rest) of pixels after an even stack split
|
|
||||||
}
|
|
||||||
|
|
||||||
/***
|
|
||||||
* Layouts
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Bottomstack layout + gaps
|
|
||||||
* https://dwm.suckless.org/patches/bottomstack/
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void
|
|
||||||
bstack(Monitor *m)
|
|
||||||
{
|
|
||||||
unsigned int i, n;
|
|
||||||
int mx = 0, my = 0, mh = 0, mw = 0;
|
|
||||||
int sx = 0, sy = 0, sh = 0, sw = 0;
|
|
||||||
float mfacts, sfacts;
|
|
||||||
int mrest, srest;
|
|
||||||
Client *c;
|
|
||||||
|
|
||||||
int oh, ov, ih, iv;
|
|
||||||
getgaps(m, &oh, &ov, &ih, &iv, &n);
|
|
||||||
|
|
||||||
if (n == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
sx = mx = m->wx + ov;
|
|
||||||
sy = my = m->wy + oh;
|
|
||||||
sh = mh = m->wh - 2*oh;
|
|
||||||
mw = m->ww - 2*ov - iv * (MIN(n, m->nmaster) - 1);
|
|
||||||
sw = m->ww - 2*ov - iv * (n - m->nmaster - 1);
|
|
||||||
|
|
||||||
if (m->nmaster && n > m->nmaster) {
|
|
||||||
sh = (mh - ih) * (1 - m->mfact);
|
|
||||||
mh = (mh - ih) * m->mfact;
|
|
||||||
sx = mx;
|
|
||||||
sy = my + mh + ih;
|
|
||||||
}
|
|
||||||
|
|
||||||
getfacts(m, mw, sw, &mfacts, &sfacts, &mrest, &srest);
|
|
||||||
|
|
||||||
for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) {
|
|
||||||
if (i < m->nmaster) {
|
|
||||||
resize(c, mx, my, (mw / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0);
|
|
||||||
mx += WIDTH(c) + iv;
|
|
||||||
} else {
|
|
||||||
resize(c, sx, sy, (sw / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), sh - (2*c->bw), 0);
|
|
||||||
sx += WIDTH(c) + iv;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Centred master layout + gaps
|
|
||||||
* https://dwm.suckless.org/patches/centeredmaster/
|
|
||||||
*/
|
|
||||||
|
|
||||||
void
|
|
||||||
centeredmaster(Monitor *m)
|
|
||||||
{
|
|
||||||
unsigned int i, n;
|
|
||||||
int mx = 0, my = 0, mh = 0, mw = 0;
|
|
||||||
int lx = 0, ly = 0, lw = 0, lh = 0;
|
|
||||||
int rx = 0, ry = 0, rw = 0, rh = 0;
|
|
||||||
float mfacts = 0, lfacts = 0, rfacts = 0;
|
|
||||||
int mtotal = 0, ltotal = 0, rtotal = 0;
|
|
||||||
int mrest = 0, lrest = 0, rrest = 0;
|
|
||||||
Client *c;
|
|
||||||
|
|
||||||
int oh, ov, ih, iv;
|
|
||||||
getgaps(m, &oh, &ov, &ih, &iv, &n);
|
|
||||||
|
|
||||||
if (n == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* initialize areas */
|
|
||||||
mx = m->wx + ov;
|
|
||||||
my = m->wy + oh;
|
|
||||||
mh = m->wh - 2*oh - ih * ((!m->nmaster ? n : MIN(n, m->nmaster)) - 1);
|
|
||||||
mw = m->ww - 2*ov;
|
|
||||||
lh = m->wh - 2*oh - ih * (((n - m->nmaster) / 2) - 1);
|
|
||||||
rh = m->wh - 2*oh - ih * (((n - m->nmaster) / 2) - ((n - m->nmaster) % 2 ? 0 : 1));
|
|
||||||
|
|
||||||
if (m->nmaster && n > m->nmaster) {
|
|
||||||
/* go mfact box in the center if more than nmaster clients */
|
|
||||||
if (n - m->nmaster > 1) {
|
|
||||||
/* ||<-S->|<---M--->|<-S->|| */
|
|
||||||
mw = (m->ww - 2*ov - 2*iv) * m->mfact;
|
|
||||||
lw = (m->ww - mw - 2*ov - 2*iv) / 2;
|
|
||||||
mx += lw + iv;
|
|
||||||
} else {
|
|
||||||
/* ||<---M--->|<-S->|| */
|
|
||||||
mw = (mw - iv) * m->mfact;
|
|
||||||
lw = m->ww - mw - iv - 2*ov;
|
|
||||||
}
|
|
||||||
rw = lw;
|
|
||||||
lx = m->wx + ov;
|
|
||||||
ly = m->wy + oh;
|
|
||||||
rx = mx + mw + iv;
|
|
||||||
ry = m->wy + oh;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* calculate facts */
|
|
||||||
for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++) {
|
|
||||||
if (!m->nmaster || n < m->nmaster)
|
|
||||||
mfacts += 1;
|
|
||||||
else if ((n - m->nmaster) % 2)
|
|
||||||
lfacts += 1; // total factor of left hand stack area
|
|
||||||
else
|
|
||||||
rfacts += 1; // total factor of right hand stack area
|
|
||||||
}
|
|
||||||
|
|
||||||
for (n = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), n++)
|
|
||||||
if (!m->nmaster || n < m->nmaster)
|
|
||||||
mtotal += mh / mfacts;
|
|
||||||
else if ((n - m->nmaster) % 2)
|
|
||||||
ltotal += lh / lfacts;
|
|
||||||
else
|
|
||||||
rtotal += rh / rfacts;
|
|
||||||
|
|
||||||
mrest = mh - mtotal;
|
|
||||||
lrest = lh - ltotal;
|
|
||||||
rrest = rh - rtotal;
|
|
||||||
|
|
||||||
for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++) {
|
|
||||||
if (!m->nmaster || i < m->nmaster) {
|
|
||||||
/* nmaster clients are stacked vertically, in the center of the screen */
|
|
||||||
resize(c, mx, my, mw - (2*c->bw), (mh / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), 0);
|
|
||||||
my += HEIGHT(c) + ih;
|
|
||||||
} else {
|
|
||||||
/* stack clients are stacked vertically */
|
|
||||||
if ((i - m->nmaster) % 2 ) {
|
|
||||||
resize(c, lx, ly, lw - (2*c->bw), (lh / lfacts) + ((i - 2*m->nmaster) < 2*lrest ? 1 : 0) - (2*c->bw), 0);
|
|
||||||
ly += HEIGHT(c) + ih;
|
|
||||||
} else {
|
|
||||||
resize(c, rx, ry, rw - (2*c->bw), (rh / rfacts) + ((i - 2*m->nmaster) < 2*rrest ? 1 : 0) - (2*c->bw), 0);
|
|
||||||
ry += HEIGHT(c) + ih;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
centeredfloatingmaster(Monitor *m)
|
|
||||||
{
|
|
||||||
unsigned int i, n;
|
|
||||||
float mfacts, sfacts;
|
|
||||||
int mrest, srest;
|
|
||||||
int mx = 0, my = 0, mh = 0, mw = 0;
|
|
||||||
int sx = 0, sy = 0, sh = 0, sw = 0;
|
|
||||||
Client *c;
|
|
||||||
|
|
||||||
float mivf = 1.0; // master inner vertical gap factor
|
|
||||||
int oh, ov, ih, iv;
|
|
||||||
getgaps(m, &oh, &ov, &ih, &iv, &n);
|
|
||||||
|
|
||||||
if (n == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
sx = mx = m->wx + ov;
|
|
||||||
sy = my = m->wy + oh;
|
|
||||||
sh = mh = m->wh - 2*oh;
|
|
||||||
mw = m->ww - 2*ov - iv*(n - 1);
|
|
||||||
sw = m->ww - 2*ov - iv*(n - m->nmaster - 1);
|
|
||||||
|
|
||||||
if (m->nmaster && n > m->nmaster) {
|
|
||||||
mivf = 0.8;
|
|
||||||
/* go mfact box in the center if more than nmaster clients */
|
|
||||||
if (m->ww > m->wh) {
|
|
||||||
mw = m->ww * m->mfact - iv*mivf*(MIN(n, m->nmaster) - 1);
|
|
||||||
mh = m->wh * 0.9 - 2*oh;
|
|
||||||
} else {
|
|
||||||
mw = m->ww * 0.9 - iv*mivf*(MIN(n, m->nmaster) - 1);
|
|
||||||
mh = m->wh * m->mfact;
|
|
||||||
}
|
|
||||||
mx = m->wx + (m->ww - mw) / 2;
|
|
||||||
my = m->wy + (m->wh - mh) / 2;
|
|
||||||
|
|
||||||
sx = m->wx + ov;
|
|
||||||
sy = m->wy + oh;
|
|
||||||
sh = m->wh - 2*oh;
|
|
||||||
}
|
|
||||||
|
|
||||||
getfacts(m, mw, sw, &mfacts, &sfacts, &mrest, &srest);
|
|
||||||
|
|
||||||
for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
|
|
||||||
if (i < m->nmaster) {
|
|
||||||
/* nmaster clients are stacked horizontally, in the center of the screen */
|
|
||||||
resize(c, mx, my, (mw / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), mh - (2*c->bw), 0);
|
|
||||||
mx += WIDTH(c) + iv*mivf;
|
|
||||||
} else {
|
|
||||||
/* stack clients are stacked horizontally */
|
|
||||||
resize(c, sx, sy, (sw / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), sh - (2*c->bw), 0);
|
|
||||||
sx += WIDTH(c) + iv;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Deck layout + gaps
|
|
||||||
* https://dwm.suckless.org/patches/deck/
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void
|
|
||||||
deck(Monitor *m)
|
|
||||||
{
|
|
||||||
unsigned int i, n;
|
|
||||||
int mx = 0, my = 0, mh = 0, mw = 0;
|
|
||||||
int sx = 0, sy = 0, sh = 0, sw = 0;
|
|
||||||
float mfacts, sfacts;
|
|
||||||
int mrest, srest;
|
|
||||||
Client *c;
|
|
||||||
|
|
||||||
int oh, ov, ih, iv;
|
|
||||||
getgaps(m, &oh, &ov, &ih, &iv, &n);
|
|
||||||
|
|
||||||
if (n == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
sx = mx = m->wx + ov;
|
|
||||||
sy = my = m->wy + oh;
|
|
||||||
sh = mh = m->wh - 2*oh - ih * (MIN(n, m->nmaster) - 1);
|
|
||||||
sw = mw = m->ww - 2*ov;
|
|
||||||
|
|
||||||
if (m->nmaster && n > m->nmaster) {
|
|
||||||
sw = (mw - iv) * (1 - m->mfact);
|
|
||||||
mw = (mw - iv) * m->mfact;
|
|
||||||
sx = mx + mw + iv;
|
|
||||||
sh = m->wh - 2*oh;
|
|
||||||
}
|
|
||||||
|
|
||||||
getfacts(m, mh, sh, &mfacts, &sfacts, &mrest, &srest);
|
|
||||||
|
|
||||||
if (n - m->nmaster > 0) /* override layout symbol */
|
|
||||||
snprintf(m->ltsymbol, sizeof m->ltsymbol, "D %d", n - m->nmaster);
|
|
||||||
|
|
||||||
for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
|
|
||||||
if (i < m->nmaster) {
|
|
||||||
resize(c, mx, my, mw - (2*c->bw), (mh / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), 0);
|
|
||||||
my += HEIGHT(c) + ih;
|
|
||||||
} else {
|
|
||||||
resize(c, sx, sy, sw - (2*c->bw), sh - (2*c->bw), 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Fibonacci layout + gaps
|
|
||||||
* https://dwm.suckless.org/patches/fibonacci/
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void
|
|
||||||
fibonacci(Monitor *m, int s)
|
|
||||||
{
|
|
||||||
unsigned int i, n;
|
|
||||||
int nx, ny, nw, nh;
|
|
||||||
int oh, ov, ih, iv;
|
|
||||||
Client *c;
|
|
||||||
|
|
||||||
getgaps(m, &oh, &ov, &ih, &iv, &n);
|
|
||||||
|
|
||||||
if (n == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
nx = m->wx + ov;
|
|
||||||
ny = oh;
|
|
||||||
nw = m->ww - 2*ov;
|
|
||||||
nh = m->wh - 2*oh;
|
|
||||||
|
|
||||||
for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next)) {
|
|
||||||
if ((i % 2 && nh / 2 > 2*c->bw)
|
|
||||||
|| (!(i % 2) && nw / 2 > 2*c->bw)) {
|
|
||||||
if (i < n - 1) {
|
|
||||||
if (i % 2)
|
|
||||||
nh = (nh - ih) / 2;
|
|
||||||
else
|
|
||||||
nw = (nw - iv) / 2;
|
|
||||||
|
|
||||||
if ((i % 4) == 2 && !s)
|
|
||||||
nx += nw + iv;
|
|
||||||
else if ((i % 4) == 3 && !s)
|
|
||||||
ny += nh + ih;
|
|
||||||
}
|
|
||||||
if ((i % 4) == 0) {
|
|
||||||
if (s)
|
|
||||||
ny += nh + ih;
|
|
||||||
else
|
|
||||||
ny -= nh + ih;
|
|
||||||
}
|
|
||||||
else if ((i % 4) == 1)
|
|
||||||
nx += nw + iv;
|
|
||||||
else if ((i % 4) == 2)
|
|
||||||
ny += nh + ih;
|
|
||||||
else if ((i % 4) == 3) {
|
|
||||||
if (s)
|
|
||||||
nx += nw + iv;
|
|
||||||
else
|
|
||||||
nx -= nw + iv;
|
|
||||||
}
|
|
||||||
if (i == 0) {
|
|
||||||
if (n != 1)
|
|
||||||
nw = (m->ww - 2*ov - iv) * m->mfact;
|
|
||||||
ny = m->wy + oh;
|
|
||||||
}
|
|
||||||
else if (i == 1)
|
|
||||||
nw = m->ww - nw - iv - 2*ov;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
resize(c, nx, ny, nw - (2*c->bw), nh - (2*c->bw), False);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
dwindle(Monitor *m)
|
|
||||||
{
|
|
||||||
fibonacci(m, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
spiral(Monitor *m)
|
|
||||||
{
|
|
||||||
fibonacci(m, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Default tile layout + gaps
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void
|
|
||||||
tile(Monitor *m)
|
|
||||||
{
|
|
||||||
unsigned int i, n;
|
|
||||||
int mx = 0, my = 0, mh = 0, mw = 0;
|
|
||||||
int sx = 0, sy = 0, sh = 0, sw = 0;
|
|
||||||
float mfacts, sfacts;
|
|
||||||
int mrest, srest;
|
|
||||||
Client *c;
|
|
||||||
|
|
||||||
|
|
||||||
int oh, ov, ih, iv;
|
|
||||||
getgaps(m, &oh, &ov, &ih, &iv, &n);
|
|
||||||
|
|
||||||
if (n == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
sx = mx = m->wx + ov;
|
|
||||||
sy = my = m->wy + oh;
|
|
||||||
mh = m->wh - 2*oh - ih * (MIN(n, m->nmaster) - 1);
|
|
||||||
sh = m->wh - 2*oh - ih * (n - m->nmaster - 1);
|
|
||||||
sw = mw = m->ww - 2*ov;
|
|
||||||
|
|
||||||
if (m->nmaster && n > m->nmaster) {
|
|
||||||
sw = (mw - iv) * (1 - m->mfact);
|
|
||||||
mw = (mw - iv) * m->mfact;
|
|
||||||
sx = mx + mw + iv;
|
|
||||||
}
|
|
||||||
|
|
||||||
getfacts(m, mh, sh, &mfacts, &sfacts, &mrest, &srest);
|
|
||||||
|
|
||||||
for (i = 0, c = nexttiled(m->clients); c; c = nexttiled(c->next), i++)
|
|
||||||
if (i < m->nmaster) {
|
|
||||||
resize(c, mx, my, mw - (2*c->bw), (mh / mfacts) + (i < mrest ? 1 : 0) - (2*c->bw), 0);
|
|
||||||
my += HEIGHT(c) + ih;
|
|
||||||
} else {
|
|
||||||
resize(c, sx, sy, sw - (2*c->bw), (sh / sfacts) + ((i - m->nmaster) < srest ? 1 : 0) - (2*c->bw), 0);
|
|
||||||
sy += HEIGHT(c) + ih;
|
|
||||||
}
|
|
||||||
}
|
|
53
.local/src2/dwmblocks/.gitignore
vendored
53
.local/src2/dwmblocks/.gitignore
vendored
|
@ -1,53 +0,0 @@
|
||||||
# Prerequisites
|
|
||||||
*.d
|
|
||||||
|
|
||||||
# Object files
|
|
||||||
*.o
|
|
||||||
*.ko
|
|
||||||
*.obj
|
|
||||||
*.elf
|
|
||||||
|
|
||||||
# Linker output
|
|
||||||
*.ilk
|
|
||||||
*.map
|
|
||||||
*.exp
|
|
||||||
|
|
||||||
# Precompiled Headers
|
|
||||||
*.gch
|
|
||||||
*.pch
|
|
||||||
|
|
||||||
# Libraries
|
|
||||||
*.lib
|
|
||||||
*.a
|
|
||||||
*.la
|
|
||||||
*.lo
|
|
||||||
|
|
||||||
# Shared objects (inc. Windows DLLs)
|
|
||||||
*.dll
|
|
||||||
*.so
|
|
||||||
*.so.*
|
|
||||||
*.dylib
|
|
||||||
|
|
||||||
# Executables
|
|
||||||
*.exe
|
|
||||||
*.out
|
|
||||||
*.app
|
|
||||||
*.i*86
|
|
||||||
*.x86_64
|
|
||||||
*.hex
|
|
||||||
dwmblocks
|
|
||||||
|
|
||||||
# Debug files
|
|
||||||
*.dSYM/
|
|
||||||
*.su
|
|
||||||
*.idb
|
|
||||||
*.pdb
|
|
||||||
|
|
||||||
# Kernel Module Compile Results
|
|
||||||
*.mod*
|
|
||||||
*.cmd
|
|
||||||
.tmp_versions/
|
|
||||||
modules.order
|
|
||||||
Module.symvers
|
|
||||||
Mkfile.old
|
|
||||||
dkms.conf
|
|
|
@ -1,3 +0,0 @@
|
||||||
github: lukesmithxyz
|
|
||||||
custom: ["https://lukesmith.xyz/donate", "https://paypal.me/lukemsmith", "https://lukesmith.xyz/crypto"]
|
|
||||||
patreon: lukesmith
|
|
|
@ -1,339 +0,0 @@
|
||||||
GNU GENERAL PUBLIC LICENSE
|
|
||||||
Version 2, June 1991
|
|
||||||
|
|
||||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
|
||||||
of this license document, but changing it is not allowed.
|
|
||||||
|
|
||||||
Preamble
|
|
||||||
|
|
||||||
The licenses for most software are designed to take away your
|
|
||||||
freedom to share and change it. By contrast, the GNU General Public
|
|
||||||
License is intended to guarantee your freedom to share and change free
|
|
||||||
software--to make sure the software is free for all its users. This
|
|
||||||
General Public License applies to most of the Free Software
|
|
||||||
Foundation's software and to any other program whose authors commit to
|
|
||||||
using it. (Some other Free Software Foundation software is covered by
|
|
||||||
the GNU Lesser General Public License instead.) You can apply it to
|
|
||||||
your programs, too.
|
|
||||||
|
|
||||||
When we speak of free software, we are referring to freedom, not
|
|
||||||
price. Our General Public Licenses are designed to make sure that you
|
|
||||||
have the freedom to distribute copies of free software (and charge for
|
|
||||||
this service if you wish), that you receive source code or can get it
|
|
||||||
if you want it, that you can change the software or use pieces of it
|
|
||||||
in new free programs; and that you know you can do these things.
|
|
||||||
|
|
||||||
To protect your rights, we need to make restrictions that forbid
|
|
||||||
anyone to deny you these rights or to ask you to surrender the rights.
|
|
||||||
These restrictions translate to certain responsibilities for you if you
|
|
||||||
distribute copies of the software, or if you modify it.
|
|
||||||
|
|
||||||
For example, if you distribute copies of such a program, whether
|
|
||||||
gratis or for a fee, you must give the recipients all the rights that
|
|
||||||
you have. You must make sure that they, too, receive or can get the
|
|
||||||
source code. And you must show them these terms so they know their
|
|
||||||
rights.
|
|
||||||
|
|
||||||
We protect your rights with two steps: (1) copyright the software, and
|
|
||||||
(2) offer you this license which gives you legal permission to copy,
|
|
||||||
distribute and/or modify the software.
|
|
||||||
|
|
||||||
Also, for each author's protection and ours, we want to make certain
|
|
||||||
that everyone understands that there is no warranty for this free
|
|
||||||
software. If the software is modified by someone else and passed on, we
|
|
||||||
want its recipients to know that what they have is not the original, so
|
|
||||||
that any problems introduced by others will not reflect on the original
|
|
||||||
authors' reputations.
|
|
||||||
|
|
||||||
Finally, any free program is threatened constantly by software
|
|
||||||
patents. We wish to avoid the danger that redistributors of a free
|
|
||||||
program will individually obtain patent licenses, in effect making the
|
|
||||||
program proprietary. To prevent this, we have made it clear that any
|
|
||||||
patent must be licensed for everyone's free use or not licensed at all.
|
|
||||||
|
|
||||||
The precise terms and conditions for copying, distribution and
|
|
||||||
modification follow.
|
|
||||||
|
|
||||||
GNU GENERAL PUBLIC LICENSE
|
|
||||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
|
||||||
|
|
||||||
0. This License applies to any program or other work which contains
|
|
||||||
a notice placed by the copyright holder saying it may be distributed
|
|
||||||
under the terms of this General Public License. The "Program", below,
|
|
||||||
refers to any such program or work, and a "work based on the Program"
|
|
||||||
means either the Program or any derivative work under copyright law:
|
|
||||||
that is to say, a work containing the Program or a portion of it,
|
|
||||||
either verbatim or with modifications and/or translated into another
|
|
||||||
language. (Hereinafter, translation is included without limitation in
|
|
||||||
the term "modification".) Each licensee is addressed as "you".
|
|
||||||
|
|
||||||
Activities other than copying, distribution and modification are not
|
|
||||||
covered by this License; they are outside its scope. The act of
|
|
||||||
running the Program is not restricted, and the output from the Program
|
|
||||||
is covered only if its contents constitute a work based on the
|
|
||||||
Program (independent of having been made by running the Program).
|
|
||||||
Whether that is true depends on what the Program does.
|
|
||||||
|
|
||||||
1. You may copy and distribute verbatim copies of the Program's
|
|
||||||
source code as you receive it, in any medium, provided that you
|
|
||||||
conspicuously and appropriately publish on each copy an appropriate
|
|
||||||
copyright notice and disclaimer of warranty; keep intact all the
|
|
||||||
notices that refer to this License and to the absence of any warranty;
|
|
||||||
and give any other recipients of the Program a copy of this License
|
|
||||||
along with the Program.
|
|
||||||
|
|
||||||
You may charge a fee for the physical act of transferring a copy, and
|
|
||||||
you may at your option offer warranty protection in exchange for a fee.
|
|
||||||
|
|
||||||
2. You may modify your copy or copies of the Program or any portion
|
|
||||||
of it, thus forming a work based on the Program, and copy and
|
|
||||||
distribute such modifications or work under the terms of Section 1
|
|
||||||
above, provided that you also meet all of these conditions:
|
|
||||||
|
|
||||||
a) You must cause the modified files to carry prominent notices
|
|
||||||
stating that you changed the files and the date of any change.
|
|
||||||
|
|
||||||
b) You must cause any work that you distribute or publish, that in
|
|
||||||
whole or in part contains or is derived from the Program or any
|
|
||||||
part thereof, to be licensed as a whole at no charge to all third
|
|
||||||
parties under the terms of this License.
|
|
||||||
|
|
||||||
c) If the modified program normally reads commands interactively
|
|
||||||
when run, you must cause it, when started running for such
|
|
||||||
interactive use in the most ordinary way, to print or display an
|
|
||||||
announcement including an appropriate copyright notice and a
|
|
||||||
notice that there is no warranty (or else, saying that you provide
|
|
||||||
a warranty) and that users may redistribute the program under
|
|
||||||
these conditions, and telling the user how to view a copy of this
|
|
||||||
License. (Exception: if the Program itself is interactive but
|
|
||||||
does not normally print such an announcement, your work based on
|
|
||||||
the Program is not required to print an announcement.)
|
|
||||||
|
|
||||||
These requirements apply to the modified work as a whole. If
|
|
||||||
identifiable sections of that work are not derived from the Program,
|
|
||||||
and can be reasonably considered independent and separate works in
|
|
||||||
themselves, then this License, and its terms, do not apply to those
|
|
||||||
sections when you distribute them as separate works. But when you
|
|
||||||
distribute the same sections as part of a whole which is a work based
|
|
||||||
on the Program, the distribution of the whole must be on the terms of
|
|
||||||
this License, whose permissions for other licensees extend to the
|
|
||||||
entire whole, and thus to each and every part regardless of who wrote it.
|
|
||||||
|
|
||||||
Thus, it is not the intent of this section to claim rights or contest
|
|
||||||
your rights to work written entirely by you; rather, the intent is to
|
|
||||||
exercise the right to control the distribution of derivative or
|
|
||||||
collective works based on the Program.
|
|
||||||
|
|
||||||
In addition, mere aggregation of another work not based on the Program
|
|
||||||
with the Program (or with a work based on the Program) on a volume of
|
|
||||||
a storage or distribution medium does not bring the other work under
|
|
||||||
the scope of this License.
|
|
||||||
|
|
||||||
3. You may copy and distribute the Program (or a work based on it,
|
|
||||||
under Section 2) in object code or executable form under the terms of
|
|
||||||
Sections 1 and 2 above provided that you also do one of the following:
|
|
||||||
|
|
||||||
a) Accompany it with the complete corresponding machine-readable
|
|
||||||
source code, which must be distributed under the terms of Sections
|
|
||||||
1 and 2 above on a medium customarily used for software interchange; or,
|
|
||||||
|
|
||||||
b) Accompany it with a written offer, valid for at least three
|
|
||||||
years, to give any third party, for a charge no more than your
|
|
||||||
cost of physically performing source distribution, a complete
|
|
||||||
machine-readable copy of the corresponding source code, to be
|
|
||||||
distributed under the terms of Sections 1 and 2 above on a medium
|
|
||||||
customarily used for software interchange; or,
|
|
||||||
|
|
||||||
c) Accompany it with the information you received as to the offer
|
|
||||||
to distribute corresponding source code. (This alternative is
|
|
||||||
allowed only for noncommercial distribution and only if you
|
|
||||||
received the program in object code or executable form with such
|
|
||||||
an offer, in accord with Subsection b above.)
|
|
||||||
|
|
||||||
The source code for a work means the preferred form of the work for
|
|
||||||
making modifications to it. For an executable work, complete source
|
|
||||||
code means all the source code for all modules it contains, plus any
|
|
||||||
associated interface definition files, plus the scripts used to
|
|
||||||
control compilation and installation of the executable. However, as a
|
|
||||||
special exception, the source code distributed need not include
|
|
||||||
anything that is normally distributed (in either source or binary
|
|
||||||
form) with the major components (compiler, kernel, and so on) of the
|
|
||||||
operating system on which the executable runs, unless that component
|
|
||||||
itself accompanies the executable.
|
|
||||||
|
|
||||||
If distribution of executable or object code is made by offering
|
|
||||||
access to copy from a designated place, then offering equivalent
|
|
||||||
access to copy the source code from the same place counts as
|
|
||||||
distribution of the source code, even though third parties are not
|
|
||||||
compelled to copy the source along with the object code.
|
|
||||||
|
|
||||||
4. You may not copy, modify, sublicense, or distribute the Program
|
|
||||||
except as expressly provided under this License. Any attempt
|
|
||||||
otherwise to copy, modify, sublicense or distribute the Program is
|
|
||||||
void, and will automatically terminate your rights under this License.
|
|
||||||
However, parties who have received copies, or rights, from you under
|
|
||||||
this License will not have their licenses terminated so long as such
|
|
||||||
parties remain in full compliance.
|
|
||||||
|
|
||||||
5. You are not required to accept this License, since you have not
|
|
||||||
signed it. However, nothing else grants you permission to modify or
|
|
||||||
distribute the Program or its derivative works. These actions are
|
|
||||||
prohibited by law if you do not accept this License. Therefore, by
|
|
||||||
modifying or distributing the Program (or any work based on the
|
|
||||||
Program), you indicate your acceptance of this License to do so, and
|
|
||||||
all its terms and conditions for copying, distributing or modifying
|
|
||||||
the Program or works based on it.
|
|
||||||
|
|
||||||
6. Each time you redistribute the Program (or any work based on the
|
|
||||||
Program), the recipient automatically receives a license from the
|
|
||||||
original licensor to copy, distribute or modify the Program subject to
|
|
||||||
these terms and conditions. You may not impose any further
|
|
||||||
restrictions on the recipients' exercise of the rights granted herein.
|
|
||||||
You are not responsible for enforcing compliance by third parties to
|
|
||||||
this License.
|
|
||||||
|
|
||||||
7. If, as a consequence of a court judgment or allegation of patent
|
|
||||||
infringement or for any other reason (not limited to patent issues),
|
|
||||||
conditions are imposed on you (whether by court order, agreement or
|
|
||||||
otherwise) that contradict the conditions of this License, they do not
|
|
||||||
excuse you from the conditions of this License. If you cannot
|
|
||||||
distribute so as to satisfy simultaneously your obligations under this
|
|
||||||
License and any other pertinent obligations, then as a consequence you
|
|
||||||
may not distribute the Program at all. For example, if a patent
|
|
||||||
license would not permit royalty-free redistribution of the Program by
|
|
||||||
all those who receive copies directly or indirectly through you, then
|
|
||||||
the only way you could satisfy both it and this License would be to
|
|
||||||
refrain entirely from distribution of the Program.
|
|
||||||
|
|
||||||
If any portion of this section is held invalid or unenforceable under
|
|
||||||
any particular circumstance, the balance of the section is intended to
|
|
||||||
apply and the section as a whole is intended to apply in other
|
|
||||||
circumstances.
|
|
||||||
|
|
||||||
It is not the purpose of this section to induce you to infringe any
|
|
||||||
patents or other property right claims or to contest validity of any
|
|
||||||
such claims; this section has the sole purpose of protecting the
|
|
||||||
integrity of the free software distribution system, which is
|
|
||||||
implemented by public license practices. Many people have made
|
|
||||||
generous contributions to the wide range of software distributed
|
|
||||||
through that system in reliance on consistent application of that
|
|
||||||
system; it is up to the author/donor to decide if he or she is willing
|
|
||||||
to distribute software through any other system and a licensee cannot
|
|
||||||
impose that choice.
|
|
||||||
|
|
||||||
This section is intended to make thoroughly clear what is believed to
|
|
||||||
be a consequence of the rest of this License.
|
|
||||||
|
|
||||||
8. If the distribution and/or use of the Program is restricted in
|
|
||||||
certain countries either by patents or by copyrighted interfaces, the
|
|
||||||
original copyright holder who places the Program under this License
|
|
||||||
may add an explicit geographical distribution limitation excluding
|
|
||||||
those countries, so that distribution is permitted only in or among
|
|
||||||
countries not thus excluded. In such case, this License incorporates
|
|
||||||
the limitation as if written in the body of this License.
|
|
||||||
|
|
||||||
9. The Free Software Foundation may publish revised and/or new versions
|
|
||||||
of the General Public License from time to time. Such new versions will
|
|
||||||
be similar in spirit to the present version, but may differ in detail to
|
|
||||||
address new problems or concerns.
|
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the Program
|
|
||||||
specifies a version number of this License which applies to it and "any
|
|
||||||
later version", you have the option of following the terms and conditions
|
|
||||||
either of that version or of any later version published by the Free
|
|
||||||
Software Foundation. If the Program does not specify a version number of
|
|
||||||
this License, you may choose any version ever published by the Free Software
|
|
||||||
Foundation.
|
|
||||||
|
|
||||||
10. If you wish to incorporate parts of the Program into other free
|
|
||||||
programs whose distribution conditions are different, write to the author
|
|
||||||
to ask for permission. For software which is copyrighted by the Free
|
|
||||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
|
||||||
make exceptions for this. Our decision will be guided by the two goals
|
|
||||||
of preserving the free status of all derivatives of our free software and
|
|
||||||
of promoting the sharing and reuse of software generally.
|
|
||||||
|
|
||||||
NO WARRANTY
|
|
||||||
|
|
||||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
|
||||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
|
||||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
|
||||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
|
||||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
|
||||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
|
||||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
|
||||||
REPAIR OR CORRECTION.
|
|
||||||
|
|
||||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
|
||||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
|
||||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
|
||||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
|
||||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
|
||||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
|
||||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
|
||||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
|
||||||
POSSIBILITY OF SUCH DAMAGES.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
How to Apply These Terms to Your New Programs
|
|
||||||
|
|
||||||
If you develop a new program, and you want it to be of the greatest
|
|
||||||
possible use to the public, the best way to achieve this is to make it
|
|
||||||
free software which everyone can redistribute and change under these terms.
|
|
||||||
|
|
||||||
To do so, attach the following notices to the program. It is safest
|
|
||||||
to attach them to the start of each source file to most effectively
|
|
||||||
convey the exclusion of warranty; and each file should have at least
|
|
||||||
the "copyright" line and a pointer to where the full notice is found.
|
|
||||||
|
|
||||||
<one line to give the program's name and a brief idea of what it does.>
|
|
||||||
Copyright (C) <year> <name of author>
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation; either version 2 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along
|
|
||||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
|
|
||||||
Also add information on how to contact you by electronic and paper mail.
|
|
||||||
|
|
||||||
If the program is interactive, make it output a short notice like this
|
|
||||||
when it starts in an interactive mode:
|
|
||||||
|
|
||||||
Gnomovision version 69, Copyright (C) year name of author
|
|
||||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
|
||||||
This is free software, and you are welcome to redistribute it
|
|
||||||
under certain conditions; type `show c' for details.
|
|
||||||
|
|
||||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
|
||||||
parts of the General Public License. Of course, the commands you use may
|
|
||||||
be called something other than `show w' and `show c'; they could even be
|
|
||||||
mouse-clicks or menu items--whatever suits your program.
|
|
||||||
|
|
||||||
You should also get your employer (if you work as a programmer) or your
|
|
||||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
|
||||||
necessary. Here is a sample; alter the names:
|
|
||||||
|
|
||||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
|
||||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
|
||||||
|
|
||||||
<signature of Ty Coon>, 1 April 1989
|
|
||||||
Ty Coon, President of Vice
|
|
||||||
|
|
||||||
This General Public License does not permit incorporating your program into
|
|
||||||
proprietary programs. If your program is a subroutine library, you may
|
|
||||||
consider it more useful to permit linking proprietary applications with the
|
|
||||||
library. If this is what you want to do, use the GNU Lesser General
|
|
||||||
Public License instead of this License.
|
|
|
@ -1,19 +0,0 @@
|
||||||
.POSIX:
|
|
||||||
|
|
||||||
PREFIX = /usr/local
|
|
||||||
CC = gcc
|
|
||||||
|
|
||||||
dwmblocks: dwmblocks.o
|
|
||||||
$(CC) dwmblocks.o -lX11 -o dwmblocks
|
|
||||||
dwmblocks.o: dwmblocks.c config.h
|
|
||||||
$(CC) -c dwmblocks.c
|
|
||||||
clean:
|
|
||||||
rm -f *.o *.gch dwmblocks
|
|
||||||
install: dwmblocks
|
|
||||||
mkdir -p $(DESTDIR)$(PREFIX)/bin
|
|
||||||
cp -f dwmblocks $(DESTDIR)$(PREFIX)/bin
|
|
||||||
chmod 755 $(DESTDIR)$(PREFIX)/bin/dwmblocks
|
|
||||||
uninstall:
|
|
||||||
rm -f $(DESTDIR)$(PREFIX)/bin/dwmblocks
|
|
||||||
|
|
||||||
.PHONY: clean install uninstall
|
|
|
@ -1,44 +0,0 @@
|
||||||
# dwmblocks
|
|
||||||
|
|
||||||
Modular status bar for dwm written in c.
|
|
||||||
|
|
||||||
# Modifying blocks
|
|
||||||
|
|
||||||
The statusbar is made from text output from commandline programs. Blocks are
|
|
||||||
added and removed by editing the config.h file.
|
|
||||||
|
|
||||||
# Luke's build
|
|
||||||
|
|
||||||
I have dwmblocks read my preexisting scripts
|
|
||||||
[here in my dotfiles repo](https://github.com/LukeSmithxyz/voidrice/tree/master/.local/bin/statusbar).
|
|
||||||
So if you want my build out of the box, download those and put them in your
|
|
||||||
`$PATH`. I do this to avoid redundancy in LARBS, both i3 and dwm use the same
|
|
||||||
statusbar scripts.
|
|
||||||
|
|
||||||
# Signaling changes
|
|
||||||
|
|
||||||
Most statusbars constantly rerun every script every several seconds to update.
|
|
||||||
This is an option here, but a superior choice is giving your module a signal
|
|
||||||
that you can signal to it to update on a relevant event, rather than having it
|
|
||||||
rerun idly.
|
|
||||||
|
|
||||||
For example, the audio module has the update signal 10 by default. Thus,
|
|
||||||
running `pkill -RTMIN+10 dwmblocks` will update it.
|
|
||||||
|
|
||||||
You can also run `kill -44 $(pidof dwmblocks)` which will have the same effect,
|
|
||||||
but is faster. Just add 34 to your typical signal number.
|
|
||||||
|
|
||||||
My volume module *never* updates on its own, instead I have this command run
|
|
||||||
along side my volume shortcuts in dwm to only update it when relevant.
|
|
||||||
|
|
||||||
Note that all modules must have different signal numbers.
|
|
||||||
|
|
||||||
# Clickable modules
|
|
||||||
|
|
||||||
Like i3blocks, this build allows you to build in additional actions into your
|
|
||||||
scripts in response to click events. See the above linked scripts for examples
|
|
||||||
of this using the `$BLOCK_BUTTON` variable.
|
|
||||||
|
|
||||||
For this feature to work, you need the appropriate patch in dwm as well. See
|
|
||||||
[here](https://dwm.suckless.org/patches/statuscmd/).
|
|
||||||
Credit for those patches goes to Daniel Bylinka (daniel.bylinka@gmail.com).
|
|
|
@ -1,32 +0,0 @@
|
||||||
//Modify this file to change what commands output to your statusbar, and recompile using the make command.
|
|
||||||
static const Block blocks[] = {
|
|
||||||
/*Icon*//*Command*/ /*Update Interval*/ /*Update Signal*/
|
|
||||||
// {"⌨","sb-kbselect", 0, 30},
|
|
||||||
{"", "cat /tmp/recordingicon 2>/dev/null", 0, 9},
|
|
||||||
{"", "sb-tasks", 10, 26},
|
|
||||||
{"", "sb-music", 0, 11},
|
|
||||||
{"", "sb-pacpackages", 0, 8},
|
|
||||||
{"", "sb-news", 0, 6},
|
|
||||||
// {"", "sb-price btc Bitcoin ", 9000, 21},
|
|
||||||
{"", "sb-torrent", 20, 7},
|
|
||||||
// {"", "sb-memory", 10, 14},
|
|
||||||
// {"", "sb-cpu", 10, 18},
|
|
||||||
// {"", "sb-moonphase", 21600, 17},
|
|
||||||
{"", "sb-mailbox", 180, 12},
|
|
||||||
{"", "sb-forecast", 3600, 5},
|
|
||||||
// {"", "sb-nettraf", 1, 16},
|
|
||||||
// {"", "sb-battery", 5, 3},
|
|
||||||
{"", "sb-volume", 0, 10},
|
|
||||||
{"", "sb-clock", 60, 1},
|
|
||||||
{"", "sb-internet", 5, 4},
|
|
||||||
// {"", "sb-help-icon", 0, 15},
|
|
||||||
};
|
|
||||||
|
|
||||||
//Sets delimiter between status commands. NULL character ('\0') means no delimiter.
|
|
||||||
static char *delim = " │ ";
|
|
||||||
|
|
||||||
// Have dwmblocks automatically recompile and run when you edit this file in
|
|
||||||
// vim with the following line in your vimrc/init.vim:
|
|
||||||
|
|
||||||
// autocmd BufWritePost ~/.local/src/dwmblocks/config.h !cd ~/.local/src/dwmblocks/; sudo make install && { killall -q dwmblocks;setsid dwmblocks & }
|
|
||||||
|
|
|
@ -1,294 +0,0 @@
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <X11/Xlib.h>
|
|
||||||
#define LENGTH(X) (sizeof(X) / sizeof (X[0]))
|
|
||||||
#define CMDLENGTH 50
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char* icon;
|
|
||||||
char* command;
|
|
||||||
unsigned int interval;
|
|
||||||
unsigned int signal;
|
|
||||||
} Block;
|
|
||||||
void sighandler(int num);
|
|
||||||
void buttonhandler(int sig, siginfo_t *si, void *ucontext);
|
|
||||||
void replace(char *str, char old, char new);
|
|
||||||
void remove_all(char *str, char to_remove);
|
|
||||||
void getcmds(int time);
|
|
||||||
#ifndef __OpenBSD__
|
|
||||||
void getsigcmds(int signal);
|
|
||||||
void setupsignals();
|
|
||||||
void sighandler(int signum);
|
|
||||||
#endif
|
|
||||||
int getstatus(char *str, char *last);
|
|
||||||
void setroot();
|
|
||||||
void statusloop();
|
|
||||||
void termhandler(int signum);
|
|
||||||
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
static Display *dpy;
|
|
||||||
static int screen;
|
|
||||||
static Window root;
|
|
||||||
static char statusbar[LENGTH(blocks)][CMDLENGTH] = {0};
|
|
||||||
static char statusstr[2][256];
|
|
||||||
static int statusContinue = 1;
|
|
||||||
static void (*writestatus) () = setroot;
|
|
||||||
|
|
||||||
void replace(char *str, char old, char new)
|
|
||||||
{
|
|
||||||
for(char * c = str; *c; c++)
|
|
||||||
if(*c == old)
|
|
||||||
*c = new;
|
|
||||||
}
|
|
||||||
|
|
||||||
// the previous function looked nice but unfortunately it didnt work if to_remove was in any position other than the last character
|
|
||||||
// theres probably still a better way of doing this
|
|
||||||
void remove_all(char *str, char to_remove) {
|
|
||||||
char *read = str;
|
|
||||||
char *write = str;
|
|
||||||
while (*read) {
|
|
||||||
if (*read != to_remove) {
|
|
||||||
*write++ = *read;
|
|
||||||
}
|
|
||||||
++read;
|
|
||||||
}
|
|
||||||
*write = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
int gcd(int a, int b)
|
|
||||||
{
|
|
||||||
int temp;
|
|
||||||
while (b > 0){
|
|
||||||
temp = a % b;
|
|
||||||
|
|
||||||
a = b;
|
|
||||||
b = temp;
|
|
||||||
}
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//opens process *cmd and stores output in *output
|
|
||||||
void getcmd(const Block *block, char *output)
|
|
||||||
{
|
|
||||||
if (block->signal)
|
|
||||||
{
|
|
||||||
output[0] = block->signal;
|
|
||||||
output++;
|
|
||||||
}
|
|
||||||
char *cmd = block->command;
|
|
||||||
FILE *cmdf = popen(cmd,"r");
|
|
||||||
if (!cmdf){
|
|
||||||
//printf("failed to run: %s, %d\n", block->command, errno);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
char tmpstr[CMDLENGTH] = "";
|
|
||||||
// TODO decide whether its better to use the last value till next time or just keep trying while the error was the interrupt
|
|
||||||
// this keeps trying to read if it got nothing and the error was an interrupt
|
|
||||||
// could also just read to a separate buffer and not move the data over if interrupted
|
|
||||||
// this way will take longer trying to complete 1 thing but will get it done
|
|
||||||
// the other way will move on to keep going with everything and the part that failed to read will be wrong till its updated again
|
|
||||||
// either way you have to save the data to a temp buffer because when it fails it writes nothing and then then it gets displayed before this finishes
|
|
||||||
char * s;
|
|
||||||
int e;
|
|
||||||
do {
|
|
||||||
errno = 0;
|
|
||||||
s = fgets(tmpstr, CMDLENGTH-(strlen(delim)+1), cmdf);
|
|
||||||
e = errno;
|
|
||||||
} while (!s && e == EINTR);
|
|
||||||
pclose(cmdf);
|
|
||||||
int i = strlen(block->icon);
|
|
||||||
strcpy(output, block->icon);
|
|
||||||
strcpy(output+i, tmpstr);
|
|
||||||
remove_all(output, '\n');
|
|
||||||
i = strlen(output);
|
|
||||||
if ((i > 0 && block != &blocks[LENGTH(blocks) - 1])){
|
|
||||||
strcat(output, delim);
|
|
||||||
}
|
|
||||||
i+=strlen(delim);
|
|
||||||
output[i++] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
void getcmds(int time)
|
|
||||||
{
|
|
||||||
const Block* current;
|
|
||||||
for(int i = 0; i < LENGTH(blocks); i++)
|
|
||||||
{
|
|
||||||
current = blocks + i;
|
|
||||||
if ((current->interval != 0 && time % current->interval == 0) || time == -1){
|
|
||||||
getcmd(current,statusbar[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef __OpenBSD__
|
|
||||||
void getsigcmds(int signal)
|
|
||||||
{
|
|
||||||
const Block *current;
|
|
||||||
for (int i = 0; i < LENGTH(blocks); i++)
|
|
||||||
{
|
|
||||||
current = blocks + i;
|
|
||||||
if (current->signal == signal){
|
|
||||||
getcmd(current,statusbar[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void setupsignals()
|
|
||||||
{
|
|
||||||
struct sigaction sa;
|
|
||||||
|
|
||||||
for(int i = SIGRTMIN; i <= SIGRTMAX; i++)
|
|
||||||
signal(i, SIG_IGN);
|
|
||||||
|
|
||||||
for(int i = 0; i < LENGTH(blocks); i++)
|
|
||||||
{
|
|
||||||
if (blocks[i].signal > 0)
|
|
||||||
{
|
|
||||||
signal(SIGRTMIN+blocks[i].signal, sighandler);
|
|
||||||
sigaddset(&sa.sa_mask, SIGRTMIN+blocks[i].signal);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sa.sa_sigaction = buttonhandler;
|
|
||||||
sa.sa_flags = SA_SIGINFO;
|
|
||||||
sigaction(SIGUSR1, &sa, NULL);
|
|
||||||
struct sigaction sigchld_action = {
|
|
||||||
.sa_handler = SIG_DFL,
|
|
||||||
.sa_flags = SA_NOCLDWAIT
|
|
||||||
};
|
|
||||||
sigaction(SIGCHLD, &sigchld_action, NULL);
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int getstatus(char *str, char *last)
|
|
||||||
{
|
|
||||||
strcpy(last, str);
|
|
||||||
str[0] = '\0';
|
|
||||||
for(int i = 0; i < LENGTH(blocks); i++) {
|
|
||||||
strcat(str, statusbar[i]);
|
|
||||||
if (i == LENGTH(blocks) - 1)
|
|
||||||
strcat(str, " ");
|
|
||||||
}
|
|
||||||
str[strlen(str)-1] = '\0';
|
|
||||||
return strcmp(str, last);//0 if they are the same
|
|
||||||
}
|
|
||||||
|
|
||||||
void setroot()
|
|
||||||
{
|
|
||||||
if (!getstatus(statusstr[0], statusstr[1]))//Only set root if text has changed.
|
|
||||||
return;
|
|
||||||
Display *d = XOpenDisplay(NULL);
|
|
||||||
if (d) {
|
|
||||||
dpy = d;
|
|
||||||
}
|
|
||||||
screen = DefaultScreen(dpy);
|
|
||||||
root = RootWindow(dpy, screen);
|
|
||||||
XStoreName(dpy, root, statusstr[0]);
|
|
||||||
XCloseDisplay(dpy);
|
|
||||||
}
|
|
||||||
|
|
||||||
void pstdout()
|
|
||||||
{
|
|
||||||
if (!getstatus(statusstr[0], statusstr[1]))//Only write out if text has changed.
|
|
||||||
return;
|
|
||||||
printf("%s\n",statusstr[0]);
|
|
||||||
fflush(stdout);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void statusloop()
|
|
||||||
{
|
|
||||||
#ifndef __OpenBSD__
|
|
||||||
setupsignals();
|
|
||||||
#endif
|
|
||||||
// first figure out the default wait interval by finding the
|
|
||||||
// greatest common denominator of the intervals
|
|
||||||
unsigned int interval = -1;
|
|
||||||
for(int i = 0; i < LENGTH(blocks); i++){
|
|
||||||
if(blocks[i].interval){
|
|
||||||
interval = gcd(blocks[i].interval, interval);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unsigned int i = 0;
|
|
||||||
int interrupted = 0;
|
|
||||||
const struct timespec sleeptime = {interval, 0};
|
|
||||||
struct timespec tosleep = sleeptime;
|
|
||||||
getcmds(-1);
|
|
||||||
while(statusContinue)
|
|
||||||
{
|
|
||||||
// sleep for tosleep (should be a sleeptime of interval seconds) and put what was left if interrupted back into tosleep
|
|
||||||
interrupted = nanosleep(&tosleep, &tosleep);
|
|
||||||
// if interrupted then just go sleep again for the remaining time
|
|
||||||
if(interrupted == -1){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// if not interrupted then do the calling and writing
|
|
||||||
getcmds(i);
|
|
||||||
writestatus();
|
|
||||||
// then increment since its actually been a second (plus the time it took the commands to run)
|
|
||||||
i += interval;
|
|
||||||
// set the time to sleep back to the sleeptime of 1s
|
|
||||||
tosleep = sleeptime;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef __OpenBSD__
|
|
||||||
void sighandler(int signum)
|
|
||||||
{
|
|
||||||
getsigcmds(signum-SIGRTMIN);
|
|
||||||
writestatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
void buttonhandler(int sig, siginfo_t *si, void *ucontext)
|
|
||||||
{
|
|
||||||
char button[2] = {'0' + si->si_value.sival_int & 0xff, '\0'};
|
|
||||||
pid_t process_id = getpid();
|
|
||||||
sig = si->si_value.sival_int >> 8;
|
|
||||||
if (fork() == 0)
|
|
||||||
{
|
|
||||||
const Block *current;
|
|
||||||
for (int i = 0; i < LENGTH(blocks); i++)
|
|
||||||
{
|
|
||||||
current = blocks + i;
|
|
||||||
if (current->signal == sig)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
char shcmd[1024];
|
|
||||||
sprintf(shcmd,"%s && kill -%d %d",current->command, current->signal+34,process_id);
|
|
||||||
char *command[] = { "/bin/sh", "-c", shcmd, NULL };
|
|
||||||
setenv("BLOCK_BUTTON", button, 1);
|
|
||||||
setsid();
|
|
||||||
execvp(command[0], command);
|
|
||||||
exit(EXIT_SUCCESS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void termhandler(int signum)
|
|
||||||
{
|
|
||||||
statusContinue = 0;
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
|
||||||
{
|
|
||||||
for(int i = 0; i < argc; i++)
|
|
||||||
{
|
|
||||||
if (!strcmp("-d",argv[i]))
|
|
||||||
delim = argv[++i];
|
|
||||||
else if(!strcmp("-p",argv[i]))
|
|
||||||
writestatus = pstdout;
|
|
||||||
}
|
|
||||||
signal(SIGTERM, termhandler);
|
|
||||||
signal(SIGINT, termhandler);
|
|
||||||
statusloop();
|
|
||||||
}
|
|
|
@ -1,77 +0,0 @@
|
||||||
diff --git a/dwmblocks.c b/dwmblocks.c
|
|
||||||
index 7d7a564..e2c5dd0 100644
|
|
||||||
--- a/dwmblocks.c
|
|
||||||
+++ b/dwmblocks.c
|
|
||||||
@@ -34,8 +34,6 @@ static int screen;
|
|
||||||
static Window root;
|
|
||||||
static char statusbar[LENGTH(blocks)][CMDLENGTH] = {0};
|
|
||||||
static char statusstr[2][256];
|
|
||||||
-static char exportstring[CMDLENGTH + 22] = "export BLOCK_BUTTON=-;";
|
|
||||||
-static int button = 0;
|
|
||||||
static int statusContinue = 1;
|
|
||||||
static void (*writestatus) () = setroot;
|
|
||||||
|
|
||||||
@@ -55,21 +53,8 @@ void getcmd(const Block *block, char *output)
|
|
||||||
output[0] = block->signal;
|
|
||||||
output++;
|
|
||||||
}
|
|
||||||
- char* cmd;
|
|
||||||
- FILE *cmdf;
|
|
||||||
- if (button)
|
|
||||||
- {
|
|
||||||
- cmd = strcat(exportstring, block->command);
|
|
||||||
- cmd[20] = '0' + button;
|
|
||||||
- button = 0;
|
|
||||||
- cmdf = popen(cmd,"r");
|
|
||||||
- cmd[22] = '\0';
|
|
||||||
- }
|
|
||||||
- else
|
|
||||||
- {
|
|
||||||
- cmd = block->command;
|
|
||||||
- cmdf = popen(cmd,"r");
|
|
||||||
- }
|
|
||||||
+ char *cmd = block->command;
|
|
||||||
+ FILE *cmdf = popen(cmd,"r");
|
|
||||||
if (!cmdf)
|
|
||||||
return;
|
|
||||||
fgets(output, CMDLENGTH, cmdf);
|
|
||||||
@@ -117,6 +102,7 @@ void setupsignals()
|
|
||||||
sa.sa_sigaction = buttonhandler;
|
|
||||||
sa.sa_flags = SA_SIGINFO;
|
|
||||||
sigaction(SIGUSR1, &sa, NULL);
|
|
||||||
+ signal(SIGCHLD, SIG_IGN);
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@@ -179,9 +165,29 @@ void sighandler(int signum)
|
|
||||||
|
|
||||||
void buttonhandler(int sig, siginfo_t *si, void *ucontext)
|
|
||||||
{
|
|
||||||
- button = si->si_value.sival_int & 0xff;
|
|
||||||
- getsigcmds(si->si_value.sival_int >> 8);
|
|
||||||
+ int button = si->si_value.sival_int & 0xff;
|
|
||||||
+ sig = si->si_value.sival_int >> 8;
|
|
||||||
+ getsigcmds(sig);
|
|
||||||
writestatus();
|
|
||||||
+ if (fork() == 0)
|
|
||||||
+ {
|
|
||||||
+ static char exportstring[CMDLENGTH + 22] = "export BLOCK_BUTTON=-;";
|
|
||||||
+ const Block *current;
|
|
||||||
+ int i;
|
|
||||||
+ for (i = 0; i < LENGTH(blocks); i++)
|
|
||||||
+ {
|
|
||||||
+ current = blocks + i;
|
|
||||||
+ if (current->signal == sig)
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+ char *cmd = strcat(exportstring, blocks[i].command);
|
|
||||||
+ cmd[20] = '0' + button;
|
|
||||||
+ char *command[] = { "/bin/sh", "-c", cmd, NULL };
|
|
||||||
+ setsid();
|
|
||||||
+ execvp(command[0], command);
|
|
||||||
+ exit(EXIT_SUCCESS);
|
|
||||||
+ cmd[22] = '\0';
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,93 +0,0 @@
|
||||||
diff --git a/dwmblocks.c b/dwmblocks.c
|
|
||||||
index 88bdfb0..7bd14df 100644
|
|
||||||
--- a/dwmblocks.c
|
|
||||||
+++ b/dwmblocks.c
|
|
||||||
@@ -14,6 +14,7 @@ typedef struct {
|
|
||||||
unsigned int signal;
|
|
||||||
} Block;
|
|
||||||
void sighandler(int num);
|
|
||||||
+void buttonhandler(int sig, siginfo_t *si, void *ucontext);
|
|
||||||
void replace(char *str, char old, char new);
|
|
||||||
void getcmds(int time);
|
|
||||||
#ifndef __OpenBSD__
|
|
||||||
@@ -34,6 +35,8 @@ static int screen;
|
|
||||||
static Window root;
|
|
||||||
static char statusbar[LENGTH(blocks)][CMDLENGTH] = {0};
|
|
||||||
static char statusstr[2][256];
|
|
||||||
+static char exportstring[CMDLENGTH + 16] = "export BUTTON=-;";
|
|
||||||
+static int button = 0;
|
|
||||||
static int statusContinue = 1;
|
|
||||||
static void (*writestatus) () = setroot;
|
|
||||||
|
|
||||||
@@ -48,16 +51,34 @@ void replace(char *str, char old, char new)
|
|
||||||
//opens process *cmd and stores output in *output
|
|
||||||
void getcmd(const Block *block, char *output)
|
|
||||||
{
|
|
||||||
+ if (block->signal)
|
|
||||||
+ {
|
|
||||||
+ output[0] = block->signal;
|
|
||||||
+ output++;
|
|
||||||
+ }
|
|
||||||
strcpy(output, block->icon);
|
|
||||||
- char *cmd = block->command;
|
|
||||||
- FILE *cmdf = popen(cmd,"r");
|
|
||||||
+ char* cmd;
|
|
||||||
+ FILE *cmdf;
|
|
||||||
+ if (button)
|
|
||||||
+ {
|
|
||||||
+ cmd = strcat(exportstring, block->command);
|
|
||||||
+ cmd[14] = '0' + button;
|
|
||||||
+ button = 0;
|
|
||||||
+ cmdf = popen(cmd,"r");
|
|
||||||
+ cmd[16] = '\0';
|
|
||||||
+ }
|
|
||||||
+ else
|
|
||||||
+ {
|
|
||||||
+ cmd = block->command;
|
|
||||||
+ cmdf = popen(cmd,"r");
|
|
||||||
+ }
|
|
||||||
if (!cmdf)
|
|
||||||
return;
|
|
||||||
char c;
|
|
||||||
int i = strlen(block->icon);
|
|
||||||
fgets(output+i, CMDLENGTH-i, cmdf);
|
|
||||||
i = strlen(output);
|
|
||||||
- if (delim != '\0' && --i)
|
|
||||||
+ if (delim != '\0' && i)
|
|
||||||
output[i++] = delim;
|
|
||||||
output[i++] = '\0';
|
|
||||||
pclose(cmdf);
|
|
||||||
@@ -88,11 +106,18 @@ void getsigcmds(int signal)
|
|
||||||
|
|
||||||
void setupsignals()
|
|
||||||
{
|
|
||||||
+ struct sigaction sa;
|
|
||||||
for(int i = 0; i < LENGTH(blocks); i++)
|
|
||||||
{
|
|
||||||
if (blocks[i].signal > 0)
|
|
||||||
+ {
|
|
||||||
signal(SIGRTMIN+blocks[i].signal, sighandler);
|
|
||||||
+ sigaddset(&sa.sa_mask, SIGRTMIN+blocks[i].signal);
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
+ sa.sa_sigaction = buttonhandler;
|
|
||||||
+ sa.sa_flags = SA_SIGINFO;
|
|
||||||
+ sigaction(SIGUSR1, &sa, NULL);
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@@ -152,6 +177,14 @@ void sighandler(int signum)
|
|
||||||
getsigcmds(signum-SIGRTMIN);
|
|
||||||
writestatus();
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+void buttonhandler(int sig, siginfo_t *si, void *ucontext)
|
|
||||||
+{
|
|
||||||
+ button = si->si_value.sival_int & 0xff;
|
|
||||||
+ getsigcmds(si->si_value.sival_int >> 8);
|
|
||||||
+ writestatus();
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void termhandler(int signum)
|
|
|
@ -1,24 +0,0 @@
|
||||||
MIT/X Consortium License
|
|
||||||
|
|
||||||
© 2015-2016 Markus Teich <markus.teich@stusta.mhn.de>
|
|
||||||
© 2014 Dimitris Papastamos <sin@2f30.org>
|
|
||||||
© 2006-2014 Anselm R Garbe <anselm@garbe.us>
|
|
||||||
© 2014-2016 Laslo Hunhold <dev@frign.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.
|
|
|
@ -1,60 +0,0 @@
|
||||||
# slock - simple screen locker
|
|
||||||
# See LICENSE file for copyright and license details.
|
|
||||||
|
|
||||||
include config.mk
|
|
||||||
|
|
||||||
SRC = slock.c ${COMPATSRC}
|
|
||||||
OBJ = ${SRC:.c=.o}
|
|
||||||
|
|
||||||
all: options slock
|
|
||||||
|
|
||||||
options:
|
|
||||||
@echo slock build options:
|
|
||||||
@echo "CFLAGS = ${CFLAGS}"
|
|
||||||
@echo "LDFLAGS = ${LDFLAGS}"
|
|
||||||
@echo "CC = ${CC}"
|
|
||||||
|
|
||||||
.c.o:
|
|
||||||
@echo CC $<
|
|
||||||
@${CC} -c ${CFLAGS} $<
|
|
||||||
|
|
||||||
${OBJ}: config.h config.mk arg.h util.h
|
|
||||||
|
|
||||||
config.h:
|
|
||||||
@echo creating $@ from config.def.h
|
|
||||||
@cp config.def.h $@
|
|
||||||
|
|
||||||
slock: ${OBJ}
|
|
||||||
@echo CC -o $@
|
|
||||||
@${CC} -o $@ ${OBJ} ${LDFLAGS}
|
|
||||||
|
|
||||||
clean:
|
|
||||||
@echo cleaning
|
|
||||||
@rm -f slock ${OBJ} slock-${VERSION}.tar.gz
|
|
||||||
|
|
||||||
dist: clean
|
|
||||||
@echo creating dist tarball
|
|
||||||
@mkdir -p slock-${VERSION}
|
|
||||||
@cp -R LICENSE Makefile README slock.1 config.mk \
|
|
||||||
${SRC} explicit_bzero.c config.def.h arg.h util.h slock-${VERSION}
|
|
||||||
@tar -cf slock-${VERSION}.tar slock-${VERSION}
|
|
||||||
@gzip slock-${VERSION}.tar
|
|
||||||
@rm -rf slock-${VERSION}
|
|
||||||
|
|
||||||
install: all
|
|
||||||
@echo installing executable file to ${DESTDIR}${PREFIX}/bin
|
|
||||||
@mkdir -p ${DESTDIR}${PREFIX}/bin
|
|
||||||
@cp -f slock ${DESTDIR}${PREFIX}/bin
|
|
||||||
@chmod 755 ${DESTDIR}${PREFIX}/bin/slock
|
|
||||||
@echo installing manual page to ${DESTDIR}${MANPREFIX}/man1
|
|
||||||
@mkdir -p ${DESTDIR}${MANPREFIX}/man1
|
|
||||||
@sed "s/VERSION/${VERSION}/g" <slock.1 >${DESTDIR}${MANPREFIX}/man1/slock.1
|
|
||||||
@chmod 644 ${DESTDIR}${MANPREFIX}/man1/slock.1
|
|
||||||
|
|
||||||
uninstall:
|
|
||||||
@echo removing executable file from ${DESTDIR}${PREFIX}/bin
|
|
||||||
@rm -f ${DESTDIR}${PREFIX}/bin/slock
|
|
||||||
@echo removing manual page from ${DESTDIR}${MANPREFIX}/man1
|
|
||||||
@rm -f ${DESTDIR}${MANPREFIX}/man1/slock.1
|
|
||||||
|
|
||||||
.PHONY: all options clean dist install uninstall
|
|
|
@ -1,24 +0,0 @@
|
||||||
slock - simple screen locker
|
|
||||||
============================
|
|
||||||
simple screen locker utility for X.
|
|
||||||
|
|
||||||
|
|
||||||
Requirements
|
|
||||||
------------
|
|
||||||
In order to build slock you need the Xlib header files.
|
|
||||||
|
|
||||||
|
|
||||||
Installation
|
|
||||||
------------
|
|
||||||
Edit config.mk to match your local setup (slock is installed into
|
|
||||||
the /usr/local namespace by default).
|
|
||||||
|
|
||||||
Afterwards enter the following command to build and install slock
|
|
||||||
(if necessary as root):
|
|
||||||
|
|
||||||
make clean install
|
|
||||||
|
|
||||||
|
|
||||||
Running slock
|
|
||||||
-------------
|
|
||||||
Simply invoke the 'slock' command. To get out of it, enter your password.
|
|
|
@ -1,65 +0,0 @@
|
||||||
/*
|
|
||||||
* 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_)
|
|
||||||
|
|
||||||
/* Handles obsolete -NUM syntax */
|
|
||||||
#define ARGNUM case '0':\
|
|
||||||
case '1':\
|
|
||||||
case '2':\
|
|
||||||
case '3':\
|
|
||||||
case '4':\
|
|
||||||
case '5':\
|
|
||||||
case '6':\
|
|
||||||
case '7':\
|
|
||||||
case '8':\
|
|
||||||
case '9'
|
|
||||||
|
|
||||||
#define ARGEND }\
|
|
||||||
}
|
|
||||||
|
|
||||||
#define ARGC() argc_
|
|
||||||
|
|
||||||
#define ARGNUMF() (brk_ = 1, estrtonum(argv[0], 0, INT_MAX))
|
|
||||||
|
|
||||||
#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])))
|
|
||||||
|
|
||||||
#define LNGARG() &argv[0][0]
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,38 +0,0 @@
|
||||||
/* user and group to drop privileges to */
|
|
||||||
static const char *user = "nobody";
|
|
||||||
static const char *group = "nogroup";
|
|
||||||
|
|
||||||
static const char *colorname[NUMCOLS] = {
|
|
||||||
[INIT] = "black", /* after initialization */
|
|
||||||
[INPUT] = "#005577", /* during input */
|
|
||||||
[FAILED] = "#CC3333", /* wrong password */
|
|
||||||
[PAM] = "#9400D3", /* waiting for PAM */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Xresources preferences to load at startup */
|
|
||||||
ResourcePref resources[] = {
|
|
||||||
{ "color0", STRING, &colorname[INIT] },
|
|
||||||
{ "color4", STRING, &colorname[INPUT] },
|
|
||||||
{ "color1", STRING, &colorname[FAILED] },
|
|
||||||
{ "color5", STRING, &colorname[PAM] },
|
|
||||||
};
|
|
||||||
|
|
||||||
/* treat a cleared input like a wrong password (color) */
|
|
||||||
static const int failonclear = 1;
|
|
||||||
|
|
||||||
/* Offset for the lockscreen message in pixels */
|
|
||||||
static const int xoffset = 1920;
|
|
||||||
static const int yoffset = 0;
|
|
||||||
|
|
||||||
/* PAM service that's used for authentication */
|
|
||||||
static const char * pam_service = "login";
|
|
||||||
|
|
||||||
/* default message */
|
|
||||||
static const char * message = "Check your xsidle.sh and xinitrc to make sure you're properly running slock";
|
|
||||||
|
|
||||||
/* text color */
|
|
||||||
static const char * text_color = "#ffffff";
|
|
||||||
|
|
||||||
/* text size (must be a valid size) */
|
|
||||||
static const char * font_name = "6x13";
|
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
# slock version
|
|
||||||
VERSION = 1.4
|
|
||||||
|
|
||||||
# Customize below to fit your system
|
|
||||||
|
|
||||||
# paths
|
|
||||||
PREFIX = /usr/local
|
|
||||||
MANPREFIX = ${PREFIX}/share/man
|
|
||||||
|
|
||||||
X11INC = /usr/X11R6/include
|
|
||||||
X11LIB = /usr/X11R6/lib
|
|
||||||
|
|
||||||
# includes and libs
|
|
||||||
INCS = -I. -I/usr/include -I${X11INC}
|
|
||||||
LIBS = -L/usr/lib -lc -lcrypt -L${X11LIB} -lX11 -lXext -lXrandr -lXinerama -lpam
|
|
||||||
|
|
||||||
# flags
|
|
||||||
CPPFLAGS = -DVERSION=\"${VERSION}\" -D_DEFAULT_SOURCE -DHAVE_SHADOW_H
|
|
||||||
CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS}
|
|
||||||
LDFLAGS = -s ${LIBS}
|
|
||||||
COMPATSRC = explicit_bzero.c
|
|
||||||
|
|
||||||
# On OpenBSD and Darwin remove -lcrypt from LIBS
|
|
||||||
#LIBS = -L/usr/lib -lc -L${X11LIB} -lX11 -lXext -lXrandr
|
|
||||||
# On *BSD remove -DHAVE_SHADOW_H from CPPFLAGS
|
|
||||||
# On NetBSD add -D_NETBSD_SOURCE to CPPFLAGS
|
|
||||||
#CPPFLAGS = -DVERSION=\"${VERSION}\" -D_BSD_SOURCE -D_NETBSD_SOURCE
|
|
||||||
# On OpenBSD set COMPATSRC to empty
|
|
||||||
#COMPATSRC =
|
|
||||||
|
|
||||||
# compiler and linker
|
|
||||||
CC = cc
|
|
|
@ -1,19 +0,0 @@
|
||||||
/* $OpenBSD: explicit_bzero.c,v 1.3 2014/06/21 02:34:26 matthew Exp $ */
|
|
||||||
/*
|
|
||||||
* Public domain.
|
|
||||||
* Written by Matthew Dempsky.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
__attribute__((weak)) void
|
|
||||||
__explicit_bzero_hook(void *buf, size_t len)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
explicit_bzero(void *buf, size_t len)
|
|
||||||
{
|
|
||||||
memset(buf, 0, len);
|
|
||||||
__explicit_bzero_hook(buf, len);
|
|
||||||
}
|
|
Binary file not shown.
Binary file not shown.
|
@ -1,284 +0,0 @@
|
||||||
From 53ba5a8d3608ca9c9c406b12c51c2bfdfb3e01d3 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Guy Shefy <guyshefyb@gmail.com>
|
|
||||||
Date: Wed, 10 Feb 2021 00:17:46 +0200
|
|
||||||
Subject: [PATCH] Add a message command with 24 bit color support
|
|
||||||
|
|
||||||
---
|
|
||||||
config.def.h | 9 +++
|
|
||||||
config.mk | 2 +-
|
|
||||||
slock.1 | 7 +++
|
|
||||||
slock.c | 154 +++++++++++++++++++++++++++++++++++++++++++++++++--
|
|
||||||
4 files changed, 167 insertions(+), 5 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/config.def.h b/config.def.h
|
|
||||||
index 9855e21..c2a0ab2 100644
|
|
||||||
--- a/config.def.h
|
|
||||||
+++ b/config.def.h
|
|
||||||
@@ -10,3 +10,12 @@ static const char *colorname[NUMCOLS] = {
|
|
||||||
|
|
||||||
/* treat a cleared input like a wrong password (color) */
|
|
||||||
static const int failonclear = 1;
|
|
||||||
+
|
|
||||||
+/* default message */
|
|
||||||
+static const char * message = "Suckless: Software that sucks less.";
|
|
||||||
+
|
|
||||||
+/* text color */
|
|
||||||
+static const char * text_color = "#ffffff";
|
|
||||||
+
|
|
||||||
+/* text size (must be a valid size) */
|
|
||||||
+static const char * font_name = "6x10";
|
|
||||||
diff --git a/config.mk b/config.mk
|
|
||||||
index 74429ae..c4ccf66 100644
|
|
||||||
--- a/config.mk
|
|
||||||
+++ b/config.mk
|
|
||||||
@@ -12,7 +12,7 @@ X11LIB = /usr/X11R6/lib
|
|
||||||
|
|
||||||
# includes and libs
|
|
||||||
INCS = -I. -I/usr/include -I${X11INC}
|
|
||||||
-LIBS = -L/usr/lib -lc -lcrypt -L${X11LIB} -lX11 -lXext -lXrandr
|
|
||||||
+LIBS = -L/usr/lib -lc -lcrypt -L${X11LIB} -lX11 -lXext -lXrandr -lXinerama
|
|
||||||
|
|
||||||
# flags
|
|
||||||
CPPFLAGS = -DVERSION=\"${VERSION}\" -D_DEFAULT_SOURCE -DHAVE_SHADOW_H
|
|
||||||
diff --git a/slock.1 b/slock.1
|
|
||||||
index 82cdcd6..946165f 100644
|
|
||||||
--- a/slock.1
|
|
||||||
+++ b/slock.1
|
|
||||||
@@ -6,6 +6,8 @@
|
|
||||||
.Sh SYNOPSIS
|
|
||||||
.Nm
|
|
||||||
.Op Fl v
|
|
||||||
+.Op Fl f
|
|
||||||
+.Op Fl m Ar message
|
|
||||||
.Op Ar cmd Op Ar arg ...
|
|
||||||
.Sh DESCRIPTION
|
|
||||||
.Nm
|
|
||||||
@@ -16,6 +18,11 @@ is executed after the screen has been locked.
|
|
||||||
.Bl -tag -width Ds
|
|
||||||
.It Fl v
|
|
||||||
Print version information to stdout and exit.
|
|
||||||
+.It Fl f
|
|
||||||
+List all valid X fonts and exit.
|
|
||||||
+.It Fl m Ar message
|
|
||||||
+Overrides default slock lock message.
|
|
||||||
+.TP
|
|
||||||
.El
|
|
||||||
.Sh SECURITY CONSIDERATIONS
|
|
||||||
To make sure a locked screen can not be bypassed by switching VTs
|
|
||||||
diff --git a/slock.c b/slock.c
|
|
||||||
index 5ae738c..b8b7fe4 100644
|
|
||||||
--- a/slock.c
|
|
||||||
+++ b/slock.c
|
|
||||||
@@ -15,6 +15,7 @@
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <X11/extensions/Xrandr.h>
|
|
||||||
+#include <X11/extensions/Xinerama.h>
|
|
||||||
#include <X11/keysym.h>
|
|
||||||
#include <X11/Xlib.h>
|
|
||||||
#include <X11/Xutil.h>
|
|
||||||
@@ -24,6 +25,9 @@
|
|
||||||
|
|
||||||
char *argv0;
|
|
||||||
|
|
||||||
+/* global count to prevent repeated error messages */
|
|
||||||
+int count_error = 0;
|
|
||||||
+
|
|
||||||
enum {
|
|
||||||
INIT,
|
|
||||||
INPUT,
|
|
||||||
@@ -83,6 +87,132 @@ dontkillme(void)
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
+static int
|
|
||||||
+readescapedint(const char *str, int *i) {
|
|
||||||
+ int n = 0;
|
|
||||||
+ if (str[*i])
|
|
||||||
+ ++*i;
|
|
||||||
+ while(str[*i] && str[*i] != ';' && str[*i] != 'm') {
|
|
||||||
+ n = 10 * n + str[*i] - '0';
|
|
||||||
+ ++*i;
|
|
||||||
+ }
|
|
||||||
+ return n;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+static void
|
|
||||||
+writemessage(Display *dpy, Window win, int screen)
|
|
||||||
+{
|
|
||||||
+ int len, line_len, width, height, s_width, s_height, i, k, tab_size, r, g, b, escaped_int, curr_line_len;
|
|
||||||
+ XGCValues gr_values;
|
|
||||||
+ XFontStruct *fontinfo;
|
|
||||||
+ XColor color, dummy;
|
|
||||||
+ XineramaScreenInfo *xsi;
|
|
||||||
+ GC gc;
|
|
||||||
+ fontinfo = XLoadQueryFont(dpy, font_name);
|
|
||||||
+
|
|
||||||
+ if (fontinfo == NULL) {
|
|
||||||
+ if (count_error == 0) {
|
|
||||||
+ fprintf(stderr, "slock: Unable to load font \"%s\"\n", font_name);
|
|
||||||
+ fprintf(stderr, "slock: Try listing fonts with 'slock -f'\n");
|
|
||||||
+ count_error++;
|
|
||||||
+ }
|
|
||||||
+ return;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ tab_size = 8 * XTextWidth(fontinfo, " ", 1);
|
|
||||||
+
|
|
||||||
+ XAllocNamedColor(dpy, DefaultColormap(dpy, screen),
|
|
||||||
+ text_color, &color, &dummy);
|
|
||||||
+
|
|
||||||
+ gr_values.font = fontinfo->fid;
|
|
||||||
+ gr_values.foreground = color.pixel;
|
|
||||||
+ gc=XCreateGC(dpy,win,GCFont+GCForeground, &gr_values);
|
|
||||||
+
|
|
||||||
+ /* To prevent "Uninitialized" warnings. */
|
|
||||||
+ xsi = NULL;
|
|
||||||
+
|
|
||||||
+ /*
|
|
||||||
+ * Start formatting and drawing text
|
|
||||||
+ */
|
|
||||||
+
|
|
||||||
+ len = strlen(message);
|
|
||||||
+
|
|
||||||
+ /* Max max line length (cut at '\n') */
|
|
||||||
+ line_len = curr_line_len = 0;
|
|
||||||
+ k = 0;
|
|
||||||
+ for (i = 0; i < len; i++) {
|
|
||||||
+ if (message[i] == '\n') {
|
|
||||||
+ curr_line_len = 0;
|
|
||||||
+ k++;
|
|
||||||
+ } else if (message[i] == 0x1b) {
|
|
||||||
+ while (i < len && message[i] != 'm') {
|
|
||||||
+ i++;
|
|
||||||
+ }
|
|
||||||
+ if (i == len)
|
|
||||||
+ die("slock: unclosed escape sequence\n");
|
|
||||||
+ } else {
|
|
||||||
+ curr_line_len += XTextWidth(fontinfo, message + i, 1);
|
|
||||||
+ if (curr_line_len > line_len)
|
|
||||||
+ line_len = curr_line_len;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ /* If there is only one line */
|
|
||||||
+ if (line_len == 0)
|
|
||||||
+ line_len = len;
|
|
||||||
+
|
|
||||||
+ if (XineramaIsActive(dpy)) {
|
|
||||||
+ xsi = XineramaQueryScreens(dpy, &i);
|
|
||||||
+ s_width = xsi[0].width;
|
|
||||||
+ s_height = xsi[0].height;
|
|
||||||
+ } else {
|
|
||||||
+ s_width = DisplayWidth(dpy, screen);
|
|
||||||
+ s_height = DisplayHeight(dpy, screen);
|
|
||||||
+ }
|
|
||||||
+ height = s_height*3/7 - (k*20)/3;
|
|
||||||
+ width = (s_width - line_len)/2;
|
|
||||||
+
|
|
||||||
+ line_len = 0;
|
|
||||||
+ /* print the text while parsing 24 bit color ANSI escape codes*/
|
|
||||||
+ for (i = k = 0; i < len; i++) {
|
|
||||||
+ switch (message[i]) {
|
|
||||||
+ case '\n':
|
|
||||||
+ line_len = 0;
|
|
||||||
+ while (message[i + 1] == '\t') {
|
|
||||||
+ line_len += tab_size;
|
|
||||||
+ i++;
|
|
||||||
+ }
|
|
||||||
+ k++;
|
|
||||||
+ break;
|
|
||||||
+ case 0x1b:
|
|
||||||
+ i++;
|
|
||||||
+ if (message[i] == '[') {
|
|
||||||
+ escaped_int = readescapedint(message, &i);
|
|
||||||
+ if (escaped_int == 39)
|
|
||||||
+ continue;
|
|
||||||
+ if (escaped_int != 38)
|
|
||||||
+ die("slock: unknown escape sequence%d\n", escaped_int);
|
|
||||||
+ if (readescapedint(message, &i) != 2)
|
|
||||||
+ die("slock: only 24 bit color supported\n");
|
|
||||||
+ r = readescapedint(message, &i) & 0xff;
|
|
||||||
+ g = readescapedint(message, &i) & 0xff;
|
|
||||||
+ b = readescapedint(message, &i) & 0xff;
|
|
||||||
+ XSetForeground(dpy, gc, r << 16 | g << 8 | b);
|
|
||||||
+ } else
|
|
||||||
+ die("slock: unknown escape sequence\n");
|
|
||||||
+ break;
|
|
||||||
+ default:
|
|
||||||
+ XDrawString(dpy, win, gc, width + line_len, height + 20 * k, message + i, 1);
|
|
||||||
+ line_len += XTextWidth(fontinfo, message + i, 1);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /* xsi should not be NULL anyway if Xinerama is active, but to be safe */
|
|
||||||
+ if (XineramaIsActive(dpy) && xsi != NULL)
|
|
||||||
+ XFree(xsi);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+
|
|
||||||
static const char *
|
|
||||||
gethash(void)
|
|
||||||
{
|
|
||||||
@@ -194,6 +324,7 @@ readpw(Display *dpy, struct xrandr *rr, struct lock **locks, int nscreens,
|
|
||||||
locks[screen]->win,
|
|
||||||
locks[screen]->colors[color]);
|
|
||||||
XClearWindow(dpy, locks[screen]->win);
|
|
||||||
+ writemessage(dpy, locks[screen]->win, screen);
|
|
||||||
}
|
|
||||||
oldc = color;
|
|
||||||
}
|
|
||||||
@@ -300,7 +431,7 @@ lockscreen(Display *dpy, struct xrandr *rr, int screen)
|
|
||||||
static void
|
|
||||||
usage(void)
|
|
||||||
{
|
|
||||||
- die("usage: slock [-v] [cmd [arg ...]]\n");
|
|
||||||
+ die("usage: slock [-v] [-f] [-m message] [cmd [arg ...]]\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
@@ -313,12 +444,25 @@ main(int argc, char **argv) {
|
|
||||||
gid_t dgid;
|
|
||||||
const char *hash;
|
|
||||||
Display *dpy;
|
|
||||||
- int s, nlocks, nscreens;
|
|
||||||
+ int i, s, nlocks, nscreens;
|
|
||||||
+ int count_fonts;
|
|
||||||
+ char **font_names;
|
|
||||||
|
|
||||||
ARGBEGIN {
|
|
||||||
case 'v':
|
|
||||||
fprintf(stderr, "slock-"VERSION"\n");
|
|
||||||
return 0;
|
|
||||||
+ case 'm':
|
|
||||||
+ message = EARGF(usage());
|
|
||||||
+ break;
|
|
||||||
+ case 'f':
|
|
||||||
+ if (!(dpy = XOpenDisplay(NULL)))
|
|
||||||
+ die("slock: cannot open display\n");
|
|
||||||
+ font_names = XListFonts(dpy, "*", 10000 /* list 10000 fonts*/, &count_fonts);
|
|
||||||
+ for (i=0; i<count_fonts; i++) {
|
|
||||||
+ fprintf(stderr, "%s\n", *(font_names+i));
|
|
||||||
+ }
|
|
||||||
+ return 0;
|
|
||||||
default:
|
|
||||||
usage();
|
|
||||||
} ARGEND
|
|
||||||
@@ -363,10 +507,12 @@ main(int argc, char **argv) {
|
|
||||||
if (!(locks = calloc(nscreens, sizeof(struct lock *))))
|
|
||||||
die("slock: out of memory\n");
|
|
||||||
for (nlocks = 0, s = 0; s < nscreens; s++) {
|
|
||||||
- if ((locks[s] = lockscreen(dpy, &rr, s)) != NULL)
|
|
||||||
+ if ((locks[s] = lockscreen(dpy, &rr, s)) != NULL) {
|
|
||||||
+ writemessage(dpy, locks[s]->win, s);
|
|
||||||
nlocks++;
|
|
||||||
- else
|
|
||||||
+ } else {
|
|
||||||
break;
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
XSync(dpy, 0);
|
|
||||||
|
|
||||||
--
|
|
||||||
2.30.0
|
|
||||||
|
|
|
@ -1,154 +0,0 @@
|
||||||
diff --git a/config.def.h b/config.def.h
|
|
||||||
index 9855e21..19e7f62 100644
|
|
||||||
--- a/config.def.h
|
|
||||||
+++ b/config.def.h
|
|
||||||
@@ -6,7 +6,11 @@ static const char *colorname[NUMCOLS] = {
|
|
||||||
[INIT] = "black", /* after initialization */
|
|
||||||
[INPUT] = "#005577", /* during input */
|
|
||||||
[FAILED] = "#CC3333", /* wrong password */
|
|
||||||
+ [PAM] = "#9400D3", /* waiting for PAM */
|
|
||||||
};
|
|
||||||
|
|
||||||
/* treat a cleared input like a wrong password (color) */
|
|
||||||
static const int failonclear = 1;
|
|
||||||
+
|
|
||||||
+/* PAM service that's used for authentication */
|
|
||||||
+static const char* pam_service = "login";
|
|
||||||
diff --git a/config.mk b/config.mk
|
|
||||||
index 74429ae..6e82074 100644
|
|
||||||
--- a/config.mk
|
|
||||||
+++ b/config.mk
|
|
||||||
@@ -12,7 +12,7 @@ X11LIB = /usr/X11R6/lib
|
|
||||||
|
|
||||||
# includes and libs
|
|
||||||
INCS = -I. -I/usr/include -I${X11INC}
|
|
||||||
-LIBS = -L/usr/lib -lc -lcrypt -L${X11LIB} -lX11 -lXext -lXrandr
|
|
||||||
+LIBS = -L/usr/lib -lc -lcrypt -L${X11LIB} -lX11 -lXext -lXrandr -lpam
|
|
||||||
|
|
||||||
# flags
|
|
||||||
CPPFLAGS = -DVERSION=\"${VERSION}\" -D_DEFAULT_SOURCE -DHAVE_SHADOW_H
|
|
||||||
diff --git a/slock.c b/slock.c
|
|
||||||
index 5ae738c..3a8da42 100644
|
|
||||||
--- a/slock.c
|
|
||||||
+++ b/slock.c
|
|
||||||
@@ -18,16 +18,22 @@
|
|
||||||
#include <X11/keysym.h>
|
|
||||||
#include <X11/Xlib.h>
|
|
||||||
#include <X11/Xutil.h>
|
|
||||||
+#include <security/pam_appl.h>
|
|
||||||
+#include <security/pam_misc.h>
|
|
||||||
|
|
||||||
#include "arg.h"
|
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
char *argv0;
|
|
||||||
+static int pam_conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr);
|
|
||||||
+struct pam_conv pamc = {pam_conv, NULL};
|
|
||||||
+char passwd[256];
|
|
||||||
|
|
||||||
enum {
|
|
||||||
INIT,
|
|
||||||
INPUT,
|
|
||||||
FAILED,
|
|
||||||
+ PAM,
|
|
||||||
NUMCOLS
|
|
||||||
};
|
|
||||||
|
|
||||||
@@ -57,6 +63,31 @@ die(const char *errstr, ...)
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
+static int
|
|
||||||
+pam_conv(int num_msg, const struct pam_message **msg,
|
|
||||||
+ struct pam_response **resp, void *appdata_ptr)
|
|
||||||
+{
|
|
||||||
+ int retval = PAM_CONV_ERR;
|
|
||||||
+ for(int i=0; i<num_msg; i++) {
|
|
||||||
+ if (msg[i]->msg_style == PAM_PROMPT_ECHO_OFF &&
|
|
||||||
+ strncmp(msg[i]->msg, "Password: ", 10) == 0) {
|
|
||||||
+ struct pam_response *resp_msg = malloc(sizeof(struct pam_response));
|
|
||||||
+ if (!resp_msg)
|
|
||||||
+ die("malloc failed\n");
|
|
||||||
+ char *password = malloc(strlen(passwd) + 1);
|
|
||||||
+ if (!password)
|
|
||||||
+ die("malloc failed\n");
|
|
||||||
+ memset(password, 0, strlen(passwd) + 1);
|
|
||||||
+ strcpy(password, passwd);
|
|
||||||
+ resp_msg->resp_retcode = 0;
|
|
||||||
+ resp_msg->resp = password;
|
|
||||||
+ resp[i] = resp_msg;
|
|
||||||
+ retval = PAM_SUCCESS;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ return retval;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
#ifdef __linux__
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <linux/oom.h>
|
|
||||||
@@ -121,6 +152,8 @@ gethash(void)
|
|
||||||
}
|
|
||||||
#endif /* HAVE_SHADOW_H */
|
|
||||||
|
|
||||||
+ /* pam, store user name */
|
|
||||||
+ hash = pw->pw_name;
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -129,11 +162,12 @@ readpw(Display *dpy, struct xrandr *rr, struct lock **locks, int nscreens,
|
|
||||||
const char *hash)
|
|
||||||
{
|
|
||||||
XRRScreenChangeNotifyEvent *rre;
|
|
||||||
- char buf[32], passwd[256], *inputhash;
|
|
||||||
- int num, screen, running, failure, oldc;
|
|
||||||
+ char buf[32];
|
|
||||||
+ int num, screen, running, failure, oldc, retval;
|
|
||||||
unsigned int len, color;
|
|
||||||
KeySym ksym;
|
|
||||||
XEvent ev;
|
|
||||||
+ pam_handle_t *pamh;
|
|
||||||
|
|
||||||
len = 0;
|
|
||||||
running = 1;
|
|
||||||
@@ -160,10 +194,26 @@ readpw(Display *dpy, struct xrandr *rr, struct lock **locks, int nscreens,
|
|
||||||
case XK_Return:
|
|
||||||
passwd[len] = '\0';
|
|
||||||
errno = 0;
|
|
||||||
- if (!(inputhash = crypt(passwd, hash)))
|
|
||||||
- fprintf(stderr, "slock: crypt: %s\n", strerror(errno));
|
|
||||||
+ retval = pam_start(pam_service, hash, &pamc, &pamh);
|
|
||||||
+ color = PAM;
|
|
||||||
+ for (screen = 0; screen < nscreens; screen++) {
|
|
||||||
+ XSetWindowBackground(dpy, locks[screen]->win, locks[screen]->colors[color]);
|
|
||||||
+ XClearWindow(dpy, locks[screen]->win);
|
|
||||||
+ XRaiseWindow(dpy, locks[screen]->win);
|
|
||||||
+ }
|
|
||||||
+ XSync(dpy, False);
|
|
||||||
+
|
|
||||||
+ if (retval == PAM_SUCCESS)
|
|
||||||
+ retval = pam_authenticate(pamh, 0);
|
|
||||||
+ if (retval == PAM_SUCCESS)
|
|
||||||
+ retval = pam_acct_mgmt(pamh, 0);
|
|
||||||
+
|
|
||||||
+ running = 1;
|
|
||||||
+ if (retval == PAM_SUCCESS)
|
|
||||||
+ running = 0;
|
|
||||||
else
|
|
||||||
- running = !!strcmp(inputhash, hash);
|
|
||||||
+ fprintf(stderr, "slock: %s\n", pam_strerror(pamh, retval));
|
|
||||||
+ pam_end(pamh, retval);
|
|
||||||
if (running) {
|
|
||||||
XBell(dpy, 100);
|
|
||||||
failure = 1;
|
|
||||||
@@ -339,10 +389,9 @@ main(int argc, char **argv) {
|
|
||||||
dontkillme();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
+ /* the contents of hash are used to transport the current user name */
|
|
||||||
hash = gethash();
|
|
||||||
errno = 0;
|
|
||||||
- if (!crypt("", hash))
|
|
||||||
- die("slock: crypt: %s\n", strerror(errno));
|
|
||||||
|
|
||||||
if (!(dpy = XOpenDisplay(NULL)))
|
|
||||||
die("slock: cannot open display\n");
|
|
|
@ -1,158 +0,0 @@
|
||||||
From 53e56c751b3f2be4154760788850c51dbffc0add Mon Sep 17 00:00:00 2001
|
|
||||||
From: Arnas Udovicius <zordsdavini@gmail.com>
|
|
||||||
Date: Tue, 26 Nov 2019 16:16:15 +0200
|
|
||||||
Subject: [PATCH] Read colors from Xresources
|
|
||||||
|
|
||||||
---
|
|
||||||
config.def.h | 14 +++++++++--
|
|
||||||
slock.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
||||||
util.h | 3 +++
|
|
||||||
3 files changed, 83 insertions(+), 2 deletions(-)
|
|
||||||
|
|
||||||
diff --git a/config.def.h b/config.def.h
|
|
||||||
index 6288856..bfc1ba0 100644
|
|
||||||
--- a/config.def.h
|
|
||||||
+++ b/config.def.h
|
|
||||||
@@ -3,11 +3,21 @@ static const char *user = "nobody";
|
|
||||||
static const char *group = "nogroup";
|
|
||||||
|
|
||||||
static const char *colorname[NUMCOLS] = {
|
|
||||||
- [INIT] = "black", /* after initialization */
|
|
||||||
- [INPUT] = "#005577", /* during input */
|
|
||||||
+ [INIT] = "black", /* after initialization */
|
|
||||||
+ [INPUT] = "#005577", /* during input */
|
|
||||||
[FAILED] = "#CC3333", /* wrong password */
|
|
||||||
[CAPS] = "red", /* CapsLock on */
|
|
||||||
};
|
|
||||||
|
|
||||||
+/*
|
|
||||||
+ * Xresources preferences to load at startup
|
|
||||||
+ */
|
|
||||||
+ResourcePref resources[] = {
|
|
||||||
+ { "color0", STRING, &colorname[INIT] },
|
|
||||||
+ { "color4", STRING, &colorname[INPUT] },
|
|
||||||
+ { "color1", STRING, &colorname[FAILED] },
|
|
||||||
+ { "color3", STRING, &colorname[CAPS] },
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
/* treat a cleared input like a wrong password (color) */
|
|
||||||
static const int failonclear = 1;
|
|
||||||
diff --git a/slock.c b/slock.c
|
|
||||||
index 5f4fb7a..2395547 100644
|
|
||||||
--- a/slock.c
|
|
||||||
+++ b/slock.c
|
|
||||||
@@ -6,6 +6,7 @@
|
|
||||||
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <errno.h>
|
|
||||||
+#include <math.h>
|
|
||||||
#include <grp.h>
|
|
||||||
#include <pwd.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
@@ -19,6 +20,7 @@
|
|
||||||
#include <X11/Xlib.h>
|
|
||||||
#include <X11/Xutil.h>
|
|
||||||
#include <X11/XKBlib.h>
|
|
||||||
+#include <X11/Xresource.h>
|
|
||||||
|
|
||||||
#include "arg.h"
|
|
||||||
#include "util.h"
|
|
||||||
@@ -46,6 +48,19 @@ struct xrandr {
|
|
||||||
int errbase;
|
|
||||||
};
|
|
||||||
|
|
||||||
+/* Xresources preferences */
|
|
||||||
+enum resource_type {
|
|
||||||
+ STRING = 0,
|
|
||||||
+ INTEGER = 1,
|
|
||||||
+ FLOAT = 2
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+typedef struct {
|
|
||||||
+ char *name;
|
|
||||||
+ enum resource_type type;
|
|
||||||
+ void *dst;
|
|
||||||
+} ResourcePref;
|
|
||||||
+
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
static void
|
|
||||||
@@ -306,6 +321,57 @@ lockscreen(Display *dpy, struct xrandr *rr, int screen)
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
+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", "slock", name);
|
|
||||||
+ snprintf(fullclass, sizeof(fullclass), "%s.%s", "Slock", 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(Display *dpy)
|
|
||||||
+{
|
|
||||||
+ char *resm;
|
|
||||||
+ XrmDatabase db;
|
|
||||||
+ ResourcePref *p;
|
|
||||||
+
|
|
||||||
+ XrmInitialize();
|
|
||||||
+ resm = XResourceManagerString(dpy);
|
|
||||||
+ if (!resm)
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ db = XrmGetStringDatabase(resm);
|
|
||||||
+ for (p = resources; p < resources + LEN(resources); p++)
|
|
||||||
+ resource_load(db, p->name, p->type, p->dst);
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
static void
|
|
||||||
usage(void)
|
|
||||||
{
|
|
||||||
@@ -364,6 +430,8 @@ main(int argc, char **argv) {
|
|
||||||
if (setuid(duid) < 0)
|
|
||||||
die("slock: setuid: %s\n", strerror(errno));
|
|
||||||
|
|
||||||
+ config_init(dpy);
|
|
||||||
+
|
|
||||||
/* check for Xrandr support */
|
|
||||||
rr.active = XRRQueryExtension(dpy, &rr.evbase, &rr.errbase);
|
|
||||||
|
|
||||||
diff --git a/util.h b/util.h
|
|
||||||
index 6f748b8..148dbc1 100644
|
|
||||||
--- a/util.h
|
|
||||||
+++ b/util.h
|
|
||||||
@@ -1,2 +1,5 @@
|
|
||||||
+/* macros */
|
|
||||||
+#define LEN(a) (sizeof(a) / sizeof(a)[0])
|
|
||||||
+
|
|
||||||
#undef explicit_bzero
|
|
||||||
void explicit_bzero(void *, size_t);
|
|
||||||
--
|
|
||||||
2.24.0
|
|
|
@ -1,46 +0,0 @@
|
||||||
.Dd 2016-08-23
|
|
||||||
.Dt SLOCK 1
|
|
||||||
.Sh NAME
|
|
||||||
.Nm slock
|
|
||||||
.Nd simple X screen locker
|
|
||||||
.Sh SYNOPSIS
|
|
||||||
.Nm
|
|
||||||
.Op Fl v
|
|
||||||
.Op Fl f
|
|
||||||
.Op Fl m Ar message
|
|
||||||
.Op Ar cmd Op Ar arg ...
|
|
||||||
.Sh DESCRIPTION
|
|
||||||
.Nm
|
|
||||||
is a simple X screen locker. If provided,
|
|
||||||
.Ar cmd Op Ar arg ...
|
|
||||||
is executed after the screen has been locked.
|
|
||||||
.Sh OPTIONS
|
|
||||||
.Bl -tag -width Ds
|
|
||||||
.It Fl v
|
|
||||||
Print version information to stdout and exit.
|
|
||||||
.It Fl f
|
|
||||||
List all valid X fonts and exit.
|
|
||||||
.It Fl m Ar message
|
|
||||||
Overrides default slock lock message.
|
|
||||||
.TP
|
|
||||||
.El
|
|
||||||
.Sh SECURITY CONSIDERATIONS
|
|
||||||
To make sure a locked screen can not be bypassed by switching VTs
|
|
||||||
or killing the X server with Ctrl+Alt+Backspace, it is recommended
|
|
||||||
to disable both in
|
|
||||||
.Xr xorg.conf 5
|
|
||||||
for maximum security:
|
|
||||||
.Bd -literal -offset left
|
|
||||||
Section "ServerFlags"
|
|
||||||
Option "DontVTSwitch" "True"
|
|
||||||
Option "DontZap" "True"
|
|
||||||
EndSection
|
|
||||||
.Ed
|
|
||||||
.Sh EXAMPLES
|
|
||||||
$
|
|
||||||
.Nm
|
|
||||||
/usr/sbin/s2ram
|
|
||||||
.Sh CUSTOMIZATION
|
|
||||||
.Nm
|
|
||||||
can be customized by creating a custom config.h from config.def.h and
|
|
||||||
(re)compiling the source code. This keeps it fast, secure and simple.
|
|
|
@ -1,579 +0,0 @@
|
||||||
/* See LICENSE file for license details. */
|
|
||||||
#define _XOPEN_SOURCE 500
|
|
||||||
#if HAVE_SHADOW_H
|
|
||||||
#include <shadow.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <math.h>
|
|
||||||
#include <grp.h>
|
|
||||||
#include <pwd.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <X11/extensions/Xrandr.h>
|
|
||||||
#include <X11/extensions/Xinerama.h>
|
|
||||||
#include <X11/keysym.h>
|
|
||||||
#include <X11/Xlib.h>
|
|
||||||
#include <X11/Xutil.h>
|
|
||||||
#include <X11/Xresource.h>
|
|
||||||
#include <security/pam_appl.h>
|
|
||||||
#include <security/pam_misc.h>
|
|
||||||
|
|
||||||
#include "arg.h"
|
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
char *argv0;
|
|
||||||
static int pam_conv(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *appdata_ptr);
|
|
||||||
struct pam_conv pamc = {pam_conv, NULL};
|
|
||||||
char passwd[256];
|
|
||||||
|
|
||||||
/* global count to prevent repeated error messages */
|
|
||||||
int count_error = 0;
|
|
||||||
|
|
||||||
enum {
|
|
||||||
INIT,
|
|
||||||
INPUT,
|
|
||||||
FAILED,
|
|
||||||
PAM,
|
|
||||||
NUMCOLS
|
|
||||||
};
|
|
||||||
|
|
||||||
struct lock {
|
|
||||||
int screen;
|
|
||||||
Window root, win;
|
|
||||||
Pixmap pmap;
|
|
||||||
unsigned long colors[NUMCOLS];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct xrandr {
|
|
||||||
int active;
|
|
||||||
int evbase;
|
|
||||||
int errbase;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Xresources preferences */
|
|
||||||
enum resource_type {
|
|
||||||
STRING = 0,
|
|
||||||
INTEGER = 1,
|
|
||||||
FLOAT = 2
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char *name;
|
|
||||||
enum resource_type type;
|
|
||||||
void *dst;
|
|
||||||
} ResourcePref;
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
static void
|
|
||||||
die(const char *errstr, ...)
|
|
||||||
{
|
|
||||||
va_list ap;
|
|
||||||
|
|
||||||
va_start(ap, errstr);
|
|
||||||
vfprintf(stderr, errstr, ap);
|
|
||||||
va_end(ap);
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
pam_conv(int num_msg, const struct pam_message **msg,
|
|
||||||
struct pam_response **resp, void *appdata_ptr)
|
|
||||||
{
|
|
||||||
int retval = PAM_CONV_ERR;
|
|
||||||
for(int i=0; i<num_msg; i++) {
|
|
||||||
if (msg[i]->msg_style == PAM_PROMPT_ECHO_OFF &&
|
|
||||||
strncmp(msg[i]->msg, "Password: ", 10) == 0) {
|
|
||||||
struct pam_response *resp_msg = malloc(sizeof(struct pam_response));
|
|
||||||
if (!resp_msg)
|
|
||||||
die("malloc failed\n");
|
|
||||||
char *password = malloc(strlen(passwd) + 1);
|
|
||||||
if (!password)
|
|
||||||
die("malloc failed\n");
|
|
||||||
memset(password, 0, strlen(passwd) + 1);
|
|
||||||
strcpy(password, passwd);
|
|
||||||
resp_msg->resp_retcode = 0;
|
|
||||||
resp_msg->resp = password;
|
|
||||||
resp[i] = resp_msg;
|
|
||||||
retval = PAM_SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
readescapedint(const char *str, int *i) {
|
|
||||||
int n = 0;
|
|
||||||
if (str[*i])
|
|
||||||
++*i;
|
|
||||||
while(str[*i] && str[*i] != ';' && str[*i] != 'm') {
|
|
||||||
n = 10 * n + str[*i] - '0';
|
|
||||||
++*i;
|
|
||||||
}
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
writemessage(Display *dpy, Window win, int screen)
|
|
||||||
{
|
|
||||||
int len, line_len, width, height, s_width, s_height, i, k, tab_size, r, g, b, escaped_int, curr_line_len;
|
|
||||||
XGCValues gr_values;
|
|
||||||
XFontStruct *fontinfo;
|
|
||||||
XColor color, dummy;
|
|
||||||
XineramaScreenInfo *xsi;
|
|
||||||
GC gc;
|
|
||||||
fontinfo = XLoadQueryFont(dpy, font_name);
|
|
||||||
|
|
||||||
if (fontinfo == NULL) {
|
|
||||||
if (count_error == 0) {
|
|
||||||
fprintf(stderr, "slock: Unable to load font \"%s\"\n", font_name);
|
|
||||||
fprintf(stderr, "slock: Try listing fonts with 'slock -f'\n");
|
|
||||||
count_error++;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
tab_size = 8 * XTextWidth(fontinfo, " ", 1);
|
|
||||||
|
|
||||||
XAllocNamedColor(dpy, DefaultColormap(dpy, screen),
|
|
||||||
text_color, &color, &dummy);
|
|
||||||
|
|
||||||
gr_values.font = fontinfo->fid;
|
|
||||||
gr_values.foreground = color.pixel;
|
|
||||||
gc=XCreateGC(dpy,win,GCFont+GCForeground, &gr_values);
|
|
||||||
|
|
||||||
/* To prevent "Uninitialized" warnings. */
|
|
||||||
xsi = NULL;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Start formatting and drawing text
|
|
||||||
*/
|
|
||||||
|
|
||||||
len = strlen(message);
|
|
||||||
|
|
||||||
/* Max max line length (cut at '\n') */
|
|
||||||
line_len = curr_line_len = 0;
|
|
||||||
k = 0;
|
|
||||||
for (i = 0; i < len; i++) {
|
|
||||||
if (message[i] == '\n') {
|
|
||||||
curr_line_len = 0;
|
|
||||||
k++;
|
|
||||||
} else if (message[i] == 0x1b) {
|
|
||||||
while (i < len && message[i] != 'm') {
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
if (i == len)
|
|
||||||
die("slock: unclosed escape sequence\n");
|
|
||||||
} else {
|
|
||||||
curr_line_len += XTextWidth(fontinfo, message + i, 1);
|
|
||||||
if (curr_line_len > line_len)
|
|
||||||
line_len = curr_line_len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* If there is only one line */
|
|
||||||
if (line_len == 0)
|
|
||||||
line_len = len;
|
|
||||||
|
|
||||||
if (XineramaIsActive(dpy)) {
|
|
||||||
xsi = XineramaQueryScreens(dpy, &i);
|
|
||||||
s_width = xsi[0].width;
|
|
||||||
s_height = xsi[0].height;
|
|
||||||
} else {
|
|
||||||
s_width = DisplayWidth(dpy, screen);
|
|
||||||
s_height = DisplayHeight(dpy, screen);
|
|
||||||
}
|
|
||||||
height = s_height*3/7 - (k*20)/3;
|
|
||||||
width = (s_width - line_len)/2;
|
|
||||||
|
|
||||||
line_len = 0;
|
|
||||||
/* print the text while parsing 24 bit color ANSI escape codes*/
|
|
||||||
for (i = k = 0; i < len; i++) {
|
|
||||||
switch (message[i]) {
|
|
||||||
case '\n':
|
|
||||||
line_len = 0;
|
|
||||||
while (message[i + 1] == '\t') {
|
|
||||||
line_len += tab_size;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
k++;
|
|
||||||
break;
|
|
||||||
case 0x1b:
|
|
||||||
i++;
|
|
||||||
if (message[i] == '[') {
|
|
||||||
escaped_int = readescapedint(message, &i);
|
|
||||||
if (escaped_int == 39)
|
|
||||||
continue;
|
|
||||||
if (escaped_int != 38)
|
|
||||||
die("slock: unknown escape sequence%d\n", escaped_int);
|
|
||||||
if (readescapedint(message, &i) != 2)
|
|
||||||
die("slock: only 24 bit color supported\n");
|
|
||||||
r = readescapedint(message, &i) & 0xff;
|
|
||||||
g = readescapedint(message, &i) & 0xff;
|
|
||||||
b = readescapedint(message, &i) & 0xff;
|
|
||||||
XSetForeground(dpy, gc, r << 16 | g << 8 | b);
|
|
||||||
} else
|
|
||||||
die("slock: unknown escape sequence\n");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
XDrawString(dpy, win, gc, width + line_len + xoffset, height + 20 * k + yoffset, message + i, 1);
|
|
||||||
line_len += XTextWidth(fontinfo, message + i, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* xsi should not be NULL anyway if Xinerama is active, but to be safe */
|
|
||||||
if (XineramaIsActive(dpy) && xsi != NULL)
|
|
||||||
XFree(xsi);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *
|
|
||||||
gethash(void)
|
|
||||||
{
|
|
||||||
struct passwd *pw;
|
|
||||||
|
|
||||||
/* Check if the current user has a password entry */
|
|
||||||
errno = 0;
|
|
||||||
if (!(pw = getpwuid(getuid()))) {
|
|
||||||
if (errno)
|
|
||||||
die("slock: getpwuid: %s\n", strerror(errno));
|
|
||||||
else
|
|
||||||
die("slock: cannot retrieve password entry\n");
|
|
||||||
}
|
|
||||||
return pw->pw_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
readpw(Display *dpy, struct xrandr *rr, struct lock **locks, int nscreens,
|
|
||||||
const char *hash)
|
|
||||||
{
|
|
||||||
XRRScreenChangeNotifyEvent *rre;
|
|
||||||
char buf[32];
|
|
||||||
int num, screen, running, failure, oldc, retval;
|
|
||||||
|
|
||||||
unsigned int len, color;
|
|
||||||
KeySym ksym;
|
|
||||||
XEvent ev;
|
|
||||||
pam_handle_t *pamh;
|
|
||||||
|
|
||||||
len = 0;
|
|
||||||
running = 1;
|
|
||||||
failure = 0;
|
|
||||||
oldc = INIT;
|
|
||||||
|
|
||||||
while (running && !XNextEvent(dpy, &ev)) {
|
|
||||||
if (ev.type == KeyPress) {
|
|
||||||
explicit_bzero(&buf, sizeof(buf));
|
|
||||||
num = XLookupString(&ev.xkey, buf, sizeof(buf), &ksym, 0);
|
|
||||||
if (IsKeypadKey(ksym)) {
|
|
||||||
if (ksym == XK_KP_Enter)
|
|
||||||
ksym = XK_Return;
|
|
||||||
else if (ksym >= XK_KP_0 && ksym <= XK_KP_9)
|
|
||||||
ksym = (ksym - XK_KP_0) + XK_0;
|
|
||||||
}
|
|
||||||
if (IsFunctionKey(ksym) ||
|
|
||||||
IsKeypadKey(ksym) ||
|
|
||||||
IsMiscFunctionKey(ksym) ||
|
|
||||||
IsPFKey(ksym) ||
|
|
||||||
IsPrivateKeypadKey(ksym))
|
|
||||||
continue;
|
|
||||||
switch (ksym) {
|
|
||||||
case XK_Return:
|
|
||||||
passwd[len] = '\0';
|
|
||||||
errno = 0;
|
|
||||||
retval = pam_start(pam_service, hash, &pamc, &pamh);
|
|
||||||
color = PAM;
|
|
||||||
for (screen = 0; screen < nscreens; screen++) {
|
|
||||||
XSetWindowBackground(dpy, locks[screen]->win, locks[screen]->colors[color]);
|
|
||||||
XClearWindow(dpy, locks[screen]->win);
|
|
||||||
XRaiseWindow(dpy, locks[screen]->win);
|
|
||||||
}
|
|
||||||
XSync(dpy, False);
|
|
||||||
|
|
||||||
if (retval == PAM_SUCCESS)
|
|
||||||
retval = pam_authenticate(pamh, 0);
|
|
||||||
if (retval == PAM_SUCCESS)
|
|
||||||
retval = pam_acct_mgmt(pamh, 0);
|
|
||||||
|
|
||||||
running = 1;
|
|
||||||
if (retval == PAM_SUCCESS)
|
|
||||||
running = 0;
|
|
||||||
else
|
|
||||||
fprintf(stderr, "slock: %s\n", pam_strerror(pamh, retval));
|
|
||||||
pam_end(pamh, retval);
|
|
||||||
if (running) {
|
|
||||||
XBell(dpy, 100);
|
|
||||||
failure = 1;
|
|
||||||
}
|
|
||||||
explicit_bzero(&passwd, sizeof(passwd));
|
|
||||||
len = 0;
|
|
||||||
break;
|
|
||||||
case XK_Escape:
|
|
||||||
explicit_bzero(&passwd, sizeof(passwd));
|
|
||||||
len = 0;
|
|
||||||
break;
|
|
||||||
case XK_BackSpace:
|
|
||||||
if (len)
|
|
||||||
passwd[--len] = '\0';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (num && !iscntrl((int)buf[0]) &&
|
|
||||||
(len + num < sizeof(passwd))) {
|
|
||||||
memcpy(passwd + len, buf, num);
|
|
||||||
len += num;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
color = len ? INPUT : ((failure || failonclear) ? FAILED : INIT);
|
|
||||||
if (running && oldc != color) {
|
|
||||||
for (screen = 0; screen < nscreens; screen++) {
|
|
||||||
XSetWindowBackground(dpy,
|
|
||||||
locks[screen]->win,
|
|
||||||
locks[screen]->colors[color]);
|
|
||||||
XClearWindow(dpy, locks[screen]->win);
|
|
||||||
writemessage(dpy, locks[screen]->win, screen);
|
|
||||||
}
|
|
||||||
oldc = color;
|
|
||||||
}
|
|
||||||
} else if (rr->active && ev.type == rr->evbase + RRScreenChangeNotify) {
|
|
||||||
rre = (XRRScreenChangeNotifyEvent*)&ev;
|
|
||||||
for (screen = 0; screen < nscreens; screen++) {
|
|
||||||
if (locks[screen]->win == rre->window) {
|
|
||||||
if (rre->rotation == RR_Rotate_90 ||
|
|
||||||
rre->rotation == RR_Rotate_270)
|
|
||||||
XResizeWindow(dpy, locks[screen]->win,
|
|
||||||
rre->height, rre->width);
|
|
||||||
else
|
|
||||||
XResizeWindow(dpy, locks[screen]->win,
|
|
||||||
rre->width, rre->height);
|
|
||||||
XClearWindow(dpy, locks[screen]->win);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (screen = 0; screen < nscreens; screen++)
|
|
||||||
XRaiseWindow(dpy, locks[screen]->win);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct lock *
|
|
||||||
lockscreen(Display *dpy, struct xrandr *rr, int screen)
|
|
||||||
{
|
|
||||||
char curs[] = {0, 0, 0, 0, 0, 0, 0, 0};
|
|
||||||
int i, ptgrab, kbgrab;
|
|
||||||
struct lock *lock;
|
|
||||||
XColor color, dummy;
|
|
||||||
XSetWindowAttributes wa;
|
|
||||||
Cursor invisible;
|
|
||||||
|
|
||||||
if (dpy == NULL || screen < 0 || !(lock = malloc(sizeof(struct lock))))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
lock->screen = screen;
|
|
||||||
lock->root = RootWindow(dpy, lock->screen);
|
|
||||||
|
|
||||||
for (i = 0; i < NUMCOLS; i++) {
|
|
||||||
XAllocNamedColor(dpy, DefaultColormap(dpy, lock->screen),
|
|
||||||
colorname[i], &color, &dummy);
|
|
||||||
lock->colors[i] = color.pixel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* init */
|
|
||||||
wa.override_redirect = 1;
|
|
||||||
wa.background_pixel = lock->colors[INIT];
|
|
||||||
lock->win = XCreateWindow(dpy, lock->root, 0, 0,
|
|
||||||
DisplayWidth(dpy, lock->screen),
|
|
||||||
DisplayHeight(dpy, lock->screen),
|
|
||||||
0, DefaultDepth(dpy, lock->screen),
|
|
||||||
CopyFromParent,
|
|
||||||
DefaultVisual(dpy, lock->screen),
|
|
||||||
CWOverrideRedirect | CWBackPixel, &wa);
|
|
||||||
lock->pmap = XCreateBitmapFromData(dpy, lock->win, curs, 8, 8);
|
|
||||||
invisible = XCreatePixmapCursor(dpy, lock->pmap, lock->pmap,
|
|
||||||
&color, &color, 0, 0);
|
|
||||||
XDefineCursor(dpy, lock->win, invisible);
|
|
||||||
|
|
||||||
/* Try to grab mouse pointer *and* keyboard for 600ms, else fail the lock */
|
|
||||||
for (i = 0, ptgrab = kbgrab = -1; i < 6; i++) {
|
|
||||||
if (ptgrab != GrabSuccess) {
|
|
||||||
ptgrab = XGrabPointer(dpy, lock->root, False,
|
|
||||||
ButtonPressMask | ButtonReleaseMask |
|
|
||||||
PointerMotionMask, GrabModeAsync,
|
|
||||||
GrabModeAsync, None, invisible, CurrentTime);
|
|
||||||
}
|
|
||||||
if (kbgrab != GrabSuccess) {
|
|
||||||
kbgrab = XGrabKeyboard(dpy, lock->root, True,
|
|
||||||
GrabModeAsync, GrabModeAsync, CurrentTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* input is grabbed: we can lock the screen */
|
|
||||||
if (ptgrab == GrabSuccess && kbgrab == GrabSuccess) {
|
|
||||||
XMapRaised(dpy, lock->win);
|
|
||||||
if (rr->active)
|
|
||||||
XRRSelectInput(dpy, lock->win, RRScreenChangeNotifyMask);
|
|
||||||
|
|
||||||
XSelectInput(dpy, lock->root, SubstructureNotifyMask);
|
|
||||||
return lock;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* retry on AlreadyGrabbed but fail on other errors */
|
|
||||||
if ((ptgrab != AlreadyGrabbed && ptgrab != GrabSuccess) ||
|
|
||||||
(kbgrab != AlreadyGrabbed && kbgrab != GrabSuccess))
|
|
||||||
break;
|
|
||||||
|
|
||||||
usleep(100000);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* we couldn't grab all input: fail out */
|
|
||||||
if (ptgrab != GrabSuccess)
|
|
||||||
fprintf(stderr, "slock: unable to grab mouse pointer for screen %d\n",
|
|
||||||
screen);
|
|
||||||
if (kbgrab != GrabSuccess)
|
|
||||||
fprintf(stderr, "slock: unable to grab keyboard for screen %d\n",
|
|
||||||
screen);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
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", "slock", name);
|
|
||||||
snprintf(fullclass, sizeof(fullclass), "%s.%s", "Slock", 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(Display *dpy)
|
|
||||||
{
|
|
||||||
char *resm;
|
|
||||||
XrmDatabase db;
|
|
||||||
ResourcePref *p;
|
|
||||||
|
|
||||||
XrmInitialize();
|
|
||||||
resm = XResourceManagerString(dpy);
|
|
||||||
if (!resm)
|
|
||||||
return;
|
|
||||||
|
|
||||||
db = XrmGetStringDatabase(resm);
|
|
||||||
for (p = resources; p < resources + LEN(resources); p++)
|
|
||||||
resource_load(db, p->name, p->type, p->dst);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
usage(void)
|
|
||||||
{
|
|
||||||
die("usage: slock [-v] [-f] [-m message] [cmd [arg ...]]\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
main(int argc, char **argv) {
|
|
||||||
struct xrandr rr;
|
|
||||||
struct lock **locks;
|
|
||||||
struct passwd *pwd;
|
|
||||||
struct group *grp;
|
|
||||||
uid_t duid;
|
|
||||||
gid_t dgid;
|
|
||||||
const char *hash;
|
|
||||||
Display *dpy;
|
|
||||||
int i, s, nlocks, nscreens;
|
|
||||||
int count_fonts;
|
|
||||||
char **font_names;
|
|
||||||
|
|
||||||
ARGBEGIN {
|
|
||||||
case 'v':
|
|
||||||
fprintf(stderr, "slock-"VERSION"\n");
|
|
||||||
return 0;
|
|
||||||
case 'm':
|
|
||||||
message = EARGF(usage());
|
|
||||||
break;
|
|
||||||
case 'f':
|
|
||||||
if (!(dpy = XOpenDisplay(NULL)))
|
|
||||||
die("slock: cannot open display\n");
|
|
||||||
font_names = XListFonts(dpy, "*", 10000 /* list 10000 fonts*/, &count_fonts);
|
|
||||||
for (i=0; i<count_fonts; i++) {
|
|
||||||
fprintf(stderr, "%s\n", *(font_names+i));
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
default:
|
|
||||||
usage();
|
|
||||||
} ARGEND
|
|
||||||
|
|
||||||
/* the contents of hash are used to transport the current user name */
|
|
||||||
hash = gethash();
|
|
||||||
errno = 0;
|
|
||||||
|
|
||||||
if (!(dpy = XOpenDisplay(NULL)))
|
|
||||||
die("slock: cannot open display\n");
|
|
||||||
|
|
||||||
/* check for Xrandr support */
|
|
||||||
rr.active = XRRQueryExtension(dpy, &rr.evbase, &rr.errbase);
|
|
||||||
|
|
||||||
/* get number of screens in display "dpy" and blank them */
|
|
||||||
nscreens = ScreenCount(dpy);
|
|
||||||
if (!(locks = calloc(nscreens, sizeof(struct lock *))))
|
|
||||||
die("slock: out of memory\n");
|
|
||||||
for (nlocks = 0, s = 0; s < nscreens; s++) {
|
|
||||||
if ((locks[s] = lockscreen(dpy, &rr, s)) != NULL) {
|
|
||||||
writemessage(dpy, locks[s]->win, s);
|
|
||||||
nlocks++;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
XSync(dpy, 0);
|
|
||||||
|
|
||||||
/* did we manage to lock everything? */
|
|
||||||
if (nlocks != nscreens)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
/* run post-lock command */
|
|
||||||
if (argc > 0) {
|
|
||||||
switch (fork()) {
|
|
||||||
case -1:
|
|
||||||
die("slock: fork failed: %s\n", strerror(errno));
|
|
||||||
case 0:
|
|
||||||
if (close(ConnectionNumber(dpy)) < 0)
|
|
||||||
die("slock: close: %s\n", strerror(errno));
|
|
||||||
execvp(argv[0], argv);
|
|
||||||
fprintf(stderr, "slock: execvp %s: %s\n", argv[0], strerror(errno));
|
|
||||||
_exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* everything is now blank. Wait for the correct password */
|
|
||||||
readpw(dpy, &rr, locks, nscreens, hash);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
Binary file not shown.
|
@ -1,6 +0,0 @@
|
||||||
/* macros */
|
|
||||||
#define LEN(a) (sizeof(a) / sizeof(a)[0])
|
|
||||||
|
|
||||||
#undef explicit_bzero
|
|
||||||
void explicit_bzero(void *, size_t);
|
|
||||||
|
|
1
dwm
Submodule
1
dwm
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 20484bf4c8f136fa5a30e8bd5b4cc84ae5b2300c
|
Loading…
Add table
Add a link
Reference in a new issue