Compare commits

...
313 Commits
Author SHA1 Message Date
Hiltjo Posthuma 32f2564dbb arg.h: remove unused ARGNUM* macros 2015-11-08 23:37:47 +01:00
Hiltjo Posthuma cc596365ac unboolify dmenu 2015-11-08 23:03:34 +01:00
Hiltjo Posthuma c9e4e152e6 Makefile: package config.def.h on make dist 2015-11-08 16:46:34 +01:00
Hiltjo Posthuma cc99007809 remove .hgtags file 2015-11-08 16:44:41 +01:00
Hiltjo Posthuma 34f549adb2 dmenu.1: clarify monitor numbers are starting from 0 (first mon) 2015-11-07 12:53:00 +01:00
Hiltjo Posthuma da0b9eb6c9 fix: multimon: always spawn client on first monitor if specified with -m 0
This was always broken.

Reproduce:
	focus client on second monitor, spawn dmenu with -m 0.

Result:
	Old wrong behaviour: dmenu spawns on second monitor (focused client).
	Now: dmenu spawns on specified monitor (first).
2015-11-07 12:43:00 +01:00
Hiltjo Posthuma 44b242c763 drw: cleanup drw_text, prevent gcc warning false-positive of unused var
... we don't allow passing text is NULL anymore either, for that behaviour
just use drw_rect() (it is used in dwm).
2015-10-20 22:56:57 +02:00
Hiltjo Posthuma e2e7fcb219 drw: simplify drw_font_xcreate and prevent a potential unneeded allocation 2015-10-20 22:55:39 +02:00
Hiltjo Posthuma 1f2226df13 drw: a valid (non-NULL) Drw and Fnt context must be passed
don't do these checks on this level. However for resource drw_*_free
we will allow it.
2015-10-20 22:53:55 +02:00
Hiltjo Posthuma 5a20b409c6 add sbase-style ecalloc(), calloc: or die
... remove intermediary variables
2015-10-20 22:51:57 +02:00
Hiltjo Posthuma 164986763a free schemes as array
this makes it slightly easier to add custom schemes aswell
2015-10-18 18:37:20 +02:00
Quentin Rameau 09d0a36e03 fix input text matching
just compare the size of the input string
2015-10-04 15:04:59 +02:00
Davide Del Zompo acbf35a5e3 fix incorrect ordering of match results
look for exact matches comparing the user input against the item text
2015-10-04 14:03:07 +02:00
Hiltjo Posthuma 240a7810e4 fix paste from clipboard (ctrl+shift+y)
from Joshua Lloret on the ML:

"attached is a small patch to enable pasting from clipboard, as well as primary.

It seems like there was already code in there to allow this, but since there was never any case to match the upper case 'Y', that inline if would always evaluate to false."
2015-10-04 12:32:07 +02:00
Hiltjo Posthuma d5ce8df9d9 minor style fix 2015-09-28 00:38:17 +02:00
FRIGN ba75bb30fa Remove function prototypes and reorder functions accordingly 2015-09-28 00:33:29 +02:00
FRIGN 10fd4f275f Untypedef struct item
Adds clarity. Typedefs for structs are definitely a discussion matter,
but there's no reason to hide a simple data-structure behind a
meaningless typedef.
2015-09-28 00:33:26 +02:00
Quentin Rameau b048eacc9d Fix the conversion from microseconds to nanoseconds 2015-09-28 00:27:09 +02:00
Quentin Rameau c42c378027 Replace deprecated usleep() with nanosleep() 2015-09-28 00:15:13 +02:00
Hiltjo Posthuma c15a95a061 config.mk: use -std=c99 2015-09-28 00:02:28 +02:00
Hiltjo Posthuma cf0fb79cd8 dmenu: style improvements
- move main to bottom, usage above main.
- dont use variable names with function prototypes.
- space before if, for, while, etc: 'if(' -> 'if ('.

this makes the code-style more consistent
2015-09-27 23:57:39 +02:00
Hiltjo Posthuma 03cb1ec55a drw style improvements
this makes the code-style more consistent aswell.
2015-09-27 23:56:02 +02:00
Hiltjo Posthuma bc20c13db0 separate program-specific c99 bool and X11
True, False are X11-specific, make sure to use c99 stdbool for
program-specific things.

... also remove left-over vim mode string in config.
2015-09-27 23:02:33 +02:00
Hiltjo Posthuma 96e60c66bc config.mk: fix _XOPEN_SOURCE=700 for getline() 2015-09-27 22:55:21 +02:00
Hiltjo Posthuma 2d2175ff6f config.mk: improve feature test check
this fixes a crash on NetBSD because it requires -D_XOPEN_SOURCE (strdup, usleep).

thanks k0ga and stateless for reporting and fixing this issue!
2015-09-27 22:38:14 +02:00
Eric Pruitt bbf7b95dc9 Fixed typo introduced by shared code 2015-08-06 12:47:51 +02:00
Hiltjo Posthuma d6742ef8a6 stest: get rid of getopt, use suckless arg.h
... also some style improvements.
2015-07-19 21:38:42 +02:00
Hiltjo Posthuma 5feb0c689d config.mk: add FREETYPELIBS and FREETYPEINC
These variables make it simpler to change the paths to this for ports.
`pkg-config` is avoided because it sucks, in particular for cross-compilation.

A commented path for *BSD is added, the Xft includes are located at:
/usr/X11R6/include there.

Also already bump the version number to 4.6, a release will come
approximately in August.
2015-07-19 20:32:08 +02:00
Hiltjo Posthuma 1c242df124 fix prompt color style how it used to be
This is the style how it was before the big Xft change. The colors were
inverted, this was not the case before the change.

Reported by "zvz" on #suckless IRC, thanks!
2015-07-19 20:29:26 +02:00
Hiltjo Posthuma 4b1fecd44e Use libdraw: add Xft and fallback-fonts support to graphics lib
- libdraw, util: add drw.{c,h}, util.{c,h} and update code.
- libdraw: fix drw_rect(): use w and h parameter.
- libdraw: print errstr if last character in string was ":" (sbase).
- libdraw: drw_clr_free() allow valid free(NULL).
- config.def.h: set default font to monospace.
- cleanup() on exit.
- LICENSE: update license string for dmenu -v to 2015.
- LICENSE: add myself to LICENSE
2015-06-27 21:47:10 +02:00
Anselm R Garbe 13a529ce63 applied Hiltjo's patch as suggested on the ml to fix ControlMask for C-j and C-m 2014-09-17 13:40:11 +02:00
Hiltjo Posthuma aa69426670 fix crash with ctrl-enter as input
reproduce: ./dmenu; send EOF; press ctrl+enter.
2014-07-30 20:07:47 +01:00
Anselm R Garbe 4c50e43df4 updated copyright notices in LICENSE and dmenu.c file 2014-05-29 18:03:53 +02:00
Anselm R Garbe 5ed5e90bfb applied Martin Kühl's inverse matching flag to stest 2013-08-13 19:15:04 +02:00
Anselm R Garbe 13f787306f applied Martti Kühne's dmenu monitor patch
https://gist.github.com/mar77i/3349298/raw/f6581ca96627f4c71c0bd1faf531daaf2a613b95/monarg.patch becomes upstream now
2013-08-02 22:30:20 +02:00
Anselm R Garbe 597d4b4337 accepted vi'is exit approach ^[ (suggested by Arkaduisz) 2013-06-28 22:06:02 +02:00
Anselm R Garbe 55c9be06ca forgot to add config.def.h, thanks William 2013-04-17 21:16:51 +02:00
Anselm R Garbe 14f72a2763 adopted Alex Sedov's config.h revival patch to tip 2013-04-17 21:04:05 +02:00
Anselm R Garbe ec64f273fb applied Alex Sedov's Tab buffer termination patch, thanks 2013-04-17 20:59:12 +02:00
Anselm R Garbe 0d12a47415 applied multisel patch to mainline 2013-04-17 20:56:54 +02:00
Quentin Glidic dec9a28863 dmenu_run: Split cache logic to dmenu_path again
This allows to run dmenu_path to update the cache using
a packager manager hook system
2012-07-30 17:02:12 +02:00
Moritz Wilhelmy 1299e41447 ignore prompt if it is empty in addition to NULL 2012-05-15 11:47:54 +02:00
Connor Lane Smith 38fccafada _POSIX_C_SOURCE=200809L 2012-04-06 16:38:01 +01:00
Connor Lane Smith 1f11faf7b5 listen for C-S-[jm] 2012-02-10 00:37:42 +00:00
Karl F 50145384c8 add ^G escape keybinding 2012-01-19 22:52:17 +00:00
Connor Lane Smith 7707111c10 remove _POSIX_C_SOURCE cflag 2012-01-18 23:56:13 +00:00
Connor Lane Smith 7f45b3f7aa update version 4.5-hg 2012-01-08 13:13:00 +01:00
anselm@garbe.us 0f91dd1c74 config.mk cleanup 2012-01-04 13:30:47 +01:00
Connor Lane Smith 3402a8d53a align M-[hjkl] closer to vi keys 2012-01-02 19:48:11 +01:00
Connor Lane Smith d3e9bd152e happy new year! 2012-01-01 20:33:56 +01:00
Connor Lane Smith b95fb20269 add Mod1Mask keybindings 2012-01-01 20:32:40 +01:00
Connor Lane Smith 6664e4233f merge stest -> default 2011-12-19 16:52:48 +01:00
Connor Lane Smith 26c78cd952 comment xdg fallback behaviour 2011-12-19 16:05:55 +01:00
Connor Lane Smith 6b1d658d12 stest: restore stream testing 2011-12-09 11:49:44 +01:00
Connor Lane Smith 56a0d1fa14 fork dmenu_run to disown child shell 2011-12-09 11:36:26 +01:00
Connor Lane Smith 32ef0f5662 stest: cleanup 2011-11-27 23:40:48 +01:00
Connor Lane Smith dcd6e771a1 stest: remove unneeded lstat 2011-11-27 23:37:01 +01:00
Connor Lane Smith 8cc28cb426 simplify stest 2011-11-27 23:35:09 +01:00
Connor Lane Smith 942199ccd0 dmenu_run: use $SHELL 2011-11-23 15:17:32 +01:00
Connor Lane Smith 3f9b10c86a set window background_pixel 2011-11-23 14:40:21 +01:00
Connor Lane Smith 5162d1b37a fix dmenu_path exec sh 2011-11-19 21:31:18 +01:00
Connor Lane Smith a02a1a6623 faster dmenu_run -f 2011-11-19 21:24:07 +01:00
Connor Lane Smith bb4424df07 replace lsx with stest 2011-11-19 19:54:55 +01:00
Connor Lane Smith 8ac44eb75a update manpage 2011-11-16 11:26:15 +01:00
Connor Lane Smith ebd94a6c00 limit direction keys in vline 2011-11-15 20:32:39 +01:00
Connor Lane Smith 2b31952731 fix C-n / C-p directions (thanks bastien) 2011-11-14 20:02:16 +01:00
Connor Lane Smith c01f36a1f3 new default colour scheme 2011-11-14 00:46:56 +01:00
Connor Lane Smith 168221b2f8 makefile: *.o depend on draw.h 2011-10-26 14:16:12 +01:00
Connor Lane Smith dc77337ef3 add paste from clipboard 2011-10-26 13:28:15 +01:00
Connor Lane Smith 7b1493a631 add lots of comments 2011-10-26 13:20:14 +01:00
Connor Lane Smith dd29c5d480 input focus: calculate areas of intersection 2011-10-26 12:14:50 +01:00
Connor Lane Smith 70b3418e3e simplify dmenu_run 2011-10-17 10:22:23 +01:00
Connor Lane Smith cf641ae496 merge xim -> default 2011-10-17 10:11:48 +01:00
Connor Lane Smith 5e0156c072 merge lsx -> default 2011-10-17 10:08:04 +01:00
Connor Lane Smith ca7ef6d2c9 use ~/.dmenu_cache if no xdg cache 2011-10-17 02:12:33 +01:00
Connor Lane Smith 7bbd4c56eb lsx: detect read errors 2011-10-17 01:44:07 +01:00
Connor Lane Smith 24565608cb xim: check for corner cases 2011-10-17 01:18:57 +01:00
Connor Lane Smith 05026fb5ce fix extra warning 2011-10-16 18:26:11 +01:00
Connor Lane Smith c71abdc65c lsx: return failure on error 2011-10-16 18:14:51 +01:00
Connor Lane Smith 4126b1e323 merge default -> lsx 2011-10-16 18:13:29 +01:00
Troels Henriksen c8f0a37638 add xim support 2011-10-16 17:21:33 +01:00
Connor Lane Smith 1cf3864464 limit lines to input 2011-10-13 20:43:59 +01:00
Connor Lane Smith 8e302717cb input focus: fix for reparenting wms 2011-10-04 21:39:56 +01:00
Connor Lane Smith e30ad490b2 fix monitor select when no focus 2011-09-30 21:08:37 +01:00
Connor Lane Smith 5020734408 merge token -> default 2011-09-20 00:11:01 +01:00
Connor Lane Smith 4c8d43ab73 tweak match 2011-09-20 00:09:20 +01:00
Connor Lane Smith 0582480801 update manpage 2011-09-20 00:06:13 +01:00
Connor Lane Smith f1848a3ef0 detect active monitor using input focus 2011-09-19 18:15:03 +01:00
Connor Lane Smith b26d3f54ee add token matching 2011-09-19 10:40:56 +01:00
Connor Lane Smith 3af80cd7d8 change version to 'hg' 2011-09-19 10:40:07 +01:00
Connor Lane Smith 4692f84ff0 dmenu_run: sh -c 2011-07-24 20:04:58 +01:00
Connor Lane Smith c805dcbeaf fix loadfont 2011-07-22 18:16:57 +01:00
Connor Lane Smith a6cbc6c9a7 Added tag 4.4 for changeset 2b105eaae831 2011-07-19 21:30:14 +01:00
Connor Lane Smith bae58f61cf add lsx.1 to dist 2011-07-19 21:30:09 +01:00
Connor Lane Smith 1636e12210 tweaks 2011-07-17 14:06:53 +01:00
Connor Lane Smith 2b92c95230 efficiency tweaks 2011-07-14 20:03:08 +01:00
Connor Lane Smith 16a0c0d52a fix extra warning 2011-07-14 20:03:00 +01:00
Connor Lane Smith 5867c53390 simpler vline 2011-07-06 13:40:36 +01:00
Connor Lane Smith 34a816f87d rebind ^N ^P 2011-07-04 16:55:09 +01:00
Connor Lane Smith 0288b576ca include limits.h 2011-06-25 17:02:14 +01:00
Connor Lane Smith 59dafc4ad6 make clean lsx 2011-06-23 22:39:20 +01:00
Connor Lane Smith 49672e9d05 merge lsx -> default 2011-06-23 20:27:28 +01:00
Connor Lane Smith 07d452e0c8 close lsx branch 2011-06-23 20:26:57 +01:00
Connor Lane Smith 88d44169e9 lsx: check snprintf 2011-06-23 20:04:50 +01:00
Connor Lane Smith f7cbe710a2 update draw.c 2011-06-18 22:11:19 +01:00
Connor Lane Smith 86e9e6f1ec simpler lsx 2011-06-18 07:50:46 +01:00
Connor Lane Smith eadf090413 new dmenu_run 2011-06-13 21:50:31 +01:00
Connor Lane Smith 8ec1b41cac add lsx.1 2011-06-13 19:32:45 +01:00
Connor Lane Smith ab3bcac0bf new lsx branch 2011-06-13 19:28:30 +01:00
Connor Lane Smith 723cbabc12 add ^M 2011-06-13 19:25:40 +01:00
Connor Lane Smith 86775cc44b Added tag 4.3.1 for changeset 34a2d77049a9 2011-05-18 17:01:59 +01:00
Connor Lane Smith 2103ae2891 bugfix 2011-05-18 17:01:44 +01:00
Connor Lane Smith b028ec0e07 Added tag 4.3 for changeset 14c79f054bdf 2011-05-18 16:21:45 +01:00
Connor Lane Smith bb3e33def3 no -m, cleanup 2011-05-18 16:20:03 +01:00
Connor Lane Smith 3a60b19514 fix possible overflow 2011-05-16 23:35:14 +01:00
Connor Lane Smith dd2f298252 fixed extra warnings 2011-05-16 12:59:31 +01:00
Connor Lane Smith 11ea52d170 portability 2011-05-15 21:54:26 +01:00
Connor Lane Smith 4354074607 efficient incremental search 2011-05-15 16:05:32 +01:00
Connor Lane Smith 4776d6dc61 match first 2011-05-15 14:21:00 +01:00
Connor Lane Smith d0051e7bb8 faster grab 2011-05-15 14:13:31 +01:00
Connor Lane Smith fb67bd666e cleanup 2011-05-15 13:58:54 +01:00
Connor Lane Smith f5bd1eed8d fast but inexact 2011-05-15 13:02:33 +01:00
Connor Lane Smith 1654d6cd62 cleanup 2011-05-15 02:37:49 +01:00
Connor Lane Smith 6cc0b0dc08 increment version 2011-05-14 23:26:41 +01:00
Connor Lane Smith b2bb6ebec9 only match links 2011-05-14 23:21:38 +01:00
Connor Lane Smith a662fc6e0a follow symlinks 2011-05-14 23:14:31 +01:00
Connor Lane Smith d066975e78 cleanup 2011-05-14 22:43:42 +01:00
Connor Lane Smith 26236a4900 whoops, wrong dmenu_path version 2011-05-14 22:12:28 +01:00
Connor Lane Smith 15505bd711 fast dmenu_path script 2011-05-14 20:43:11 +01:00
Connor Lane Smith 86468aafe5 instant ^E 2011-05-14 18:39:27 +01:00
Connor Lane Smith be9afce035 fix typo 2011-05-14 17:47:12 +01:00
Connor Lane Smith 3c067598fc use array for items 2011-05-14 17:46:20 +01:00
Connor Lane Smith 86019c5855 fixed xinerama corner case 2011-05-12 13:17:41 +01:00
Connor Lane Smith 0291c722fb fixed -m bug (thanks Rob) 2011-05-11 12:25:50 +01:00
Connor Lane Smith e0e6b071c6 fast grab patch (thanks Rob) 2011-05-08 15:15:24 +01:00
Connor Lane Smith cd3b4915c3 helpful errors 2011-05-06 21:13:02 +01:00
Connor Lane Smith 210b303941 paring 2011-05-05 15:46:48 +01:00
Connor Lane Smith 47e3e8be7b update license 2011-01-07 18:55:00 +00:00
Connor Lane Smith d515d2758f cache option in config.mk 2011-01-07 18:54:40 +00:00
Connor Lane Smith a8ea79715f gmake spews 2010-12-01 20:25:10 +00:00
Connor Lane Smith 3e0a141016 posix makefile 2010-12-01 20:23:16 +00:00
Anselm R Garbe cbd8257914 Added tag 4.2.1 for changeset abb6579a324f 2010-11-20 09:25:08 +00:00
Anselm R Garbe 22cf9626c7 fixed dist target bug 2010-11-20 09:25:04 +00:00
Anselm R Garbe 9e13ecabe8 Added tag 4.2 for changeset 379813a051f0 2010-11-19 11:51:01 +00:00
Connor Lane Smith 266f3dd311 removed unnecessary defines 2010-11-17 04:51:30 +00:00
Connor Lane Smith 8d9ade36de moved main, updated args 2010-11-17 04:33:34 +00:00
Connor Lane Smith da81f57f6d fixed config.mk dep 2010-11-12 00:30:03 +00:00
Connor Lane Smith c1241bcba3 updated manpage 2010-11-12 00:01:54 +00:00
Connor Lane Smith eeba6221b1 rebound paste to ^Y 2010-11-12 00:00:32 +00:00
Connor Lane Smith a0a99d10e1 removed libdc dependence 2010-11-11 23:56:39 +00:00
Connor Lane Smith 7cf66b443a -m flag to fix dwm selmon bug 2010-11-02 12:15:15 +00:00
Connor Lane Smith 038a78a3f4 updated manpage 2010-10-08 23:40:11 +01:00
Connor Lane Smith e0add428d2 cleaned up 2010-10-08 23:36:45 +01:00
Connor Lane Smith bf7b8e37ee dmenu_path.c (shell is a bottleneck) 2010-10-08 23:24:22 +01:00
Connor Lane Smith 610a0a8d12 fixed linking bug (thanks Jacob Nixdorf) & iscntrl corner case 2010-09-13 14:22:02 +01:00
Connor Lane Smith f0818217b3 simplification 2010-09-11 19:48:10 +01:00
Connor Lane Smith 3c366bd73d update to libdc, fixed utf8 bug 2010-09-11 13:37:01 +01:00
Connor Lane Smith 75a19c35bd arrow offset 2010-08-20 19:57:13 +01:00
Connor Lane Smith a5f31f5707 fixed width bug 2010-08-20 19:42:58 +01:00
Connor Lane Smith b81c1e88cd rebound paste, removed useless max widths 2010-08-20 13:50:44 +01:00
Connor Lane Smith 5376113039 new libdraw 2010-08-19 16:43:39 +01:00
Connor Lane Smith c7a8f17bd2 new libdraw 2010-08-19 16:17:57 +01:00
Connor Lane Smith 128d4cf376 resorted globals 2010-08-18 17:35:23 +01:00
Connor Lane Smith e4fdaba88d signed ints, ignore negative -l value 2010-08-18 17:33:34 +01:00
Connor Lane Smith 849f1dd7a3 fixed insert segfault, added nextrune 2010-08-12 15:35:51 +01:00
Connor Lane Smith 402dc2bc95 fixed paste 2010-08-11 15:02:03 +01:00
Connor Lane Smith 00a60cb7b2 new libdraw, replaced cistrstr with fstrstr, simpler readstdin 2010-08-11 14:24:25 +01:00
Connor Lane Smith e149c531b8 more efficient initfont 2010-08-10 18:09:02 +01:00
Connor Lane Smith 605e9b6c03 reverted calcoffsets 2010-08-10 14:14:37 +01:00
Connor Lane Smith caf5246268 simplifications 2010-08-10 13:38:49 +01:00
Connor Lane Smith 93af72e116 cursor fix + style 2010-08-09 11:54:46 +01:00
Connor Lane Smith 0b8072a5a9 added ^D, removed ^M 2010-08-06 14:16:08 +01:00
Connor Lane Smith 31ffcd3b9a new libdraw, typo fixes 2010-08-05 15:41:56 +01:00
Connor Lane Smith 9cf07b4b9b another typo fix (thanks, Gene Auyeung) 2010-08-03 18:19:59 +01:00
Connor Lane Smith 7a2782d02d typo fix 2010-08-03 17:29:53 +01:00
Connor Lane Smith 1c91c2a99c cleaned up 2010-08-03 17:18:24 +01:00
Connor Lane Smith b7695fa98c merged *{h,v} functions 2010-08-03 17:10:29 +01:00
Connor Lane Smith b54c179d58 retyped promptw 2010-08-02 15:13:33 +01:00
Connor Lane Smith 06c18808b6 replaced promptw 2010-08-02 14:49:14 +01:00
Connor Lane Smith a7aee433cc fixed bugs, no more config.h, updated manpage, new libdraw 2010-08-02 14:22:54 +01:00
Connor Lane Smith a3606ecb0e updated manpage, added paste, cleaned up, new libdraw 2010-07-31 14:56:27 +01:00
Connor Lane Smith 7d5fe17391 merged dmenu & dinput (clunky interface) 2010-07-30 13:40:56 +01:00
Connor Lane Smith 7f36736d11 underline match 2010-07-30 10:26:12 +01:00
Connor Lane Smith 115c01b74e new libdraw 2010-07-30 10:25:55 +01:00
Connor Lane Smith d77340ed53 fixed vlist select 2010-07-30 09:18:35 +01:00
Connor Lane Smith da7a799121 updated to libdraw tip 2010-07-27 13:40:32 +01:00
Connor Lane Smith 855a566319 added dmenu.h, common.c 2010-07-02 06:49:05 +01:00
Connor Lane Smith 29e8faed6c updated to new libdraw 2010-07-02 05:50:19 +01:00
Connor Lane Smith d9c24564d2 atexit cleanup 2010-07-02 03:44:01 +01:00
Connor Lane Smith 6ba5103df4 removed -e flag (too buggy), cleaned up 2010-06-30 22:42:15 +01:00
Connor Lane Smith 309d071df5 fixed no-input invisible text bug 2010-06-30 10:45:24 +01:00
Connor Lane Smith 26b9f3de0f libdraw now has own repo 2010-06-30 01:36:15 +01:00
Connor Lane Smith 7afd296c40 resizing vlist, new dinput binding 2010-06-30 00:52:14 +01:00
Connor Lane Smith cc8b3b999b cleaned up 2010-06-30 00:05:32 +01:00
Connor Lane Smith f2abaf8b30 decosmetics 2010-06-29 19:19:20 +01:00
Connor Lane Smith 340b176de6 dinput with dmenu flags, fixed usage & -v, cosmetics 2010-06-29 16:07:31 +01:00
Connor Lane Smith 18dcf73896 extended libdraw 2010-06-28 06:09:34 +01:00
Connor Lane Smith 9f3b0c6ea8 cleaned up 2010-06-25 04:33:41 +01:00
Connor Lane Smith 4508fd2c4e moved draw.c to libdraw.a 2010-06-24 17:44:35 +01:00
Connor Lane Smith 723361fa12 removed colors from dc 2010-06-24 16:24:04 +01:00
Connor Lane Smith 96c65400cc decoupled draw.c from dmenu & dinput 2010-06-24 16:18:18 +01:00
Connor Lane Smith 6c1d0e4d60 fixed offsets, updated eprint, cleaned up 2010-06-24 14:22:34 +01:00
Connor Lane Smith 6efe1932be fixed static symbols in config.def.h 2010-06-24 11:30:30 +01:00
Connor Lane Smith 8f7b62e2b6 fixed makefile 2010-06-23 14:29:32 +01:00
Connor Lane Smith 2ec16d9cb2 cleaned up 2010-06-23 13:49:24 +01:00
Connor Lane Smith 146bc23c11 cleaned up 2010-06-23 13:31:11 +01:00
Connor Lane Smith 595e797660 added draw.h 2010-06-23 13:29:15 +01:00
Connor Lane Smith bba30e2686 overlapping code 2010-06-23 12:42:08 +01:00
Connor Lane Smith 08b264393d typo fixes 2010-06-23 12:15:07 +01:00
Connor Lane Smith b4e63454e5 initial dmenu / dinput separation 2010-06-23 12:04:54 +01:00
Connor Lane Smith bff1526d31 fixed vlist cursor 2010-06-22 10:45:07 +01:00
Connor Lane Smith 9a33a72c6a updated manpage, changed keybinds
M- binds tend to be wm level, and there were up to 3 binds for the same action
M-{hjkl} also no longer made sense in vlist mode
2010-06-20 15:04:15 +01:00
Connor Lane Smith 97797d90a6 cleaned up 2010-06-20 01:19:17 +01:00
Connor Lane Smith 4983707c70 added ^K, optimisations 2010-06-20 00:44:26 +01:00
Connor Lane Smith 4229fb7b78 added sselp requirement to readme 2010-06-19 21:44:32 +01:00
Connor Lane Smith b27ffbd78b cleaned up 2010-06-16 15:36:17 +01:00
Connor Lane Smith 6366f94e36 fixed vlist paging, cleaned up 2010-06-11 09:24:33 +01:00
Connor Lane Smith 645f1d0dfc updated manpage 2010-06-09 10:13:26 +01:00
Anselm R Garbe d7d14e53da Added tag 4.1.1 for changeset 72749a826cab 2010-05-29 12:56:37 +01:00
Anselm R Garbe 851672cadc prepared bugfix release 4.1.1 2010-05-29 12:56:33 +01:00
Anselm R Garbe 504b797be8 applied Ramils patch 2010-05-29 12:55:38 +01:00
Anselm R Garbe 503ca75af4 Added tag 4.1 for changeset 844587572673 2010-05-28 11:42:54 +01:00
Anselm R Garbe 8623bf5d19 prepared dmenu-4.1 release 2010-05-28 11:42:49 +01:00
Connor Lane Smith 5bc288b2b1 fixed vlist alignment 2010-05-05 11:42:39 +01:00
Connor Lane Smith a6835349df cleaning up 2010-05-02 23:17:02 +01:00
Connor Lane Smith 518c9b72d1 fixed bad parenting, simpler vlist 2010-04-14 17:35:19 +00:00
Connor Lane Smith 09db46f54f fixed ^U cursor support 2010-04-13 20:14:45 +00:00
Connor Lane Smith e3623cd7f2 fixed 3 bugs and some inconsistency 2010-04-07 16:15:34 +00:00
Anselm R Garbe 0ba3bae981 applied Troels' patch, thanks Troels! 2010-04-01 21:40:11 +01:00
Anselm R Garbe ebeb4e4752 added Connor to LICENSE file 2010-04-01 21:32:06 +01:00
Anselm R Garbe 3472085f59 commited Connor's sanity patch 2010-04-01 21:31:09 +01:00
pancake 7ffe519816 apply nibble patch removing per-item length limit 2010-04-01 19:30:21 +02:00
pancake 29686bd1b8 add ^a and ^e keybindings 2010-04-01 19:10:41 +02:00
Anselm R Garbe 052ffae192 applied Connor's subwindow patch 2010-03-31 22:43:49 +01:00
Anselm R Garbe eededaa76f applied Connor's next nice patch, thanks a lot! 2010-03-31 22:37:41 +01:00
anselm@garbe.us 8e3e61170b applied cls' patch, thanks Connor! 2010-03-22 07:50:26 +00:00
Anselm R Garbe 37236f8840 applied Connor's patch, thanks! 2010-03-07 08:32:16 +00:00
Anselm R Garbe 7082ba1e10 this is only a temporary workaround, the command executed by -p must be configurable through some switch, that was the initial idea, just using sselp is too limited, I'll look into the other issues soon 2009-12-05 16:52:53 +00:00
Anselm R Garbe 569a1f925a applied cursor, vertical and paste patches for upcoming 4.1 dmenu version (due to the fact that surf is using dmenu as well) 2009-11-28 12:28:15 +00:00
Anselm R Garbe 0f4d3ffdb5 Added tag 4.0 for changeset 78f9f72cc9c6 2009-04-18 12:50:12 +01:00
Anselm R Garbe a1ad9c2a1c applied Matthias Christian Ott's sanity fixes (thanks a lot!) 2009-02-21 19:21:54 +00:00
a@null 51224dcb79 next release will be 4.0 2008-12-12 19:58:52 +00:00
a@null 4e74263ba0 minor modification 2008-12-09 21:55:47 +00:00
Anselm R Garbe bab59a9807 Added tag 3.9 for changeset 21a1ed9a69b9 2008-09-09 20:45:07 +01:00
Anselm R Garbe ef00902fd9 simplified initfont 2008-08-29 10:09:40 +01:00
Anselm R Garbe 3e60c5d836 reverted setlocale() call 2008-08-25 09:38:19 +01:00
Anselm R Garbe c24f22a36b removed artifact from wmii menu 2008-08-23 09:33:56 +01:00
Anselm R Garbe 44e372bb31 fixed a problem when backporting dwm's drawtext() 2008-08-18 19:24:29 +01:00
Anselm R Garbe 17232f493b abc... 2008-08-18 10:20:53 +01:00
Anselm R Garbe b95e61c9b7 removed the i = textnw... as remarked by Martin Hurton 2008-08-18 10:17:15 +01:00
Anselm R Garbe cf7e4c15a9 backported drawtext() simplifications to dmenu 2008-08-18 10:03:28 +01:00
Anselm R Garbe c43c692a4d getting rid of setlocale(), it doesn't seem to make sense with Xmb, artifact of Xutf8 times 2008-08-18 09:31:01 +01:00
Anselm R Garbe abd9fbb79a Added tag 3.8 for changeset 644b0798fccc 2008-07-29 19:20:53 +01:00
Anselm R Garbe 698ec259af similiar change as in dwm 2008-07-18 20:20:19 +01:00
Anselm R Garbe 88efbf3dd1 removed compiler warning if XINERAMA is disabled 2008-07-17 17:40:42 +01:00
Anselm R Garbe 4d8a646958 got rid of compile time xidx, grabbing the mouse pointer instead, falling back to screen 0 if no pointer available 2008-07-16 18:38:53 +01:00
Anselm R Garbe b89a9501c7 reverted uint/ulong introduction 2008-07-16 18:18:38 +01:00
Anselm R Garbe 65d655b371 minor update regarding locale support 2008-06-30 10:00:00 +01:00
Anselm R Garbe 2cef0ddb01 removed emalloc, used only once so obsolete 2008-06-21 16:43:12 +01:00
Anselm R Garbe 3f244b1d52 minor fix 2008-06-19 09:18:17 +01:00
Anselm R Garbe a6945d5094 Added tag 3.7 for changeset 0508a3a6ee10 2008-06-18 18:21:45 +01:00
Anselm R Garbe 8911aa1060 minor fix 2008-06-18 18:20:21 +01:00
Anselm R Garbe d2305e4b13 reusing config.h's color values, note we have to use const char *, instead of const char [] here, because the pointer might change 2008-06-14 10:55:13 +01:00
Anselm R Garbe fcf26a38f1 using xidx 2008-06-13 12:04:04 +01:00
Anselm R Garbe 4fc6cbe608 yet another cosmetic change 2008-06-13 11:53:53 +01:00
Anselm R Garbe a45f106d3c cosmetic fixes 2008-06-13 11:46:50 +01:00
Anselm R Garbe 596033b781 s/unsigned int/uint/, s/unsigned long/ulong/ 2008-05-22 11:15:11 +01:00
Anselm R Garbe 357558798c foo 2008-05-20 15:07:42 +01:00
anselm@anselm1 1f6af5e78f added Xinerama support to dmenu, reverted -b behavior, removed -x, -y, -w 2008-05-19 20:29:32 +01:00
Anselm R Garbe f3617bd7ca no exe should be unquoted, agreed to Peter Hartlich 2008-04-10 18:12:00 +01:00
Anselm R Garbe 096fb3723b fixed unquoted dmenu_run $exe-use reported by Jukka 2008-04-10 16:46:32 +01:00
Anselm R Garbe 6423288394 though sticking to |uniq 2008-04-09 23:32:46 +01:00
Anselm R Garbe 7195e941c1 re-applied Peter Hartlich's and Jukkas dmenu-related patches, for odd reasons they disappeared 2008-04-09 23:31:49 +01:00
anselm@anselm1 12805b69ac Added tag 3.6 for changeset 0bc2751d06e8 2008-04-03 21:56:42 +01:00
Sander van Dijk 1538bb7426 fix typo 2008-03-25 19:18:16 +01:00
Anselm R Garbe cbe5e88e4f using limits.h 2008-03-25 10:18:17 +00:00
Anselm R Garbe 2fe3ccdf58 bugfix of the -0 case in dmenu (thanks to Sander for his hint) 2008-03-25 09:43:34 +00:00
Anselm R Garbe 07d82c0c2a applied Jukkas hotfix 2008-03-24 15:56:41 +00:00
Sander van Dijk e7423f8fc6 more cosmetics 2008-03-23 22:06:09 +01:00
Sander van Dijk 61976c292b cosmetics 2008-03-23 21:17:35 +01:00
Sander van Dijk 63c9e30a76 made some whitespacing consistent. 2008-03-23 21:11:42 +01:00
sander@localhost 015f51ac46 removed unused variable nitem. 2008-03-23 12:09:29 +01:00
anselm@anselm1 542c58d8d0 several performance tweaks 2008-03-22 14:52:00 +00:00
Anselm R Garbe 745c46d8fa fixed match() to prefer prefix-matches to strstr-matches in the match list, extended the -y handling, next version is 3.6 2008-03-18 16:52:51 +00:00
Anselm R Garbe d058e83570 Added tag 3.5 for changeset 05e5bd706b3b 2008-03-13 16:53:25 +00:00
Anselm R Garbe 301b4e5591 applied next patch of Sander 2008-03-13 12:02:29 +00:00
anselm@anselm1 38b866ba34 applied Sanders patch 2008-03-12 21:37:43 +00:00
Anselm R Garbe 540a78761b removed ido-matching, changed behavior of -i meaning case insensitive matching now, commented -x, -y, -w arguments in dmenu.1 2008-03-12 15:41:19 +00:00
Anselm R Garbe 7804354106 removed set 2008-02-12 09:42:48 +00:00
anselm@aab 6d8e68dcfd updated 2008-02-11 11:22:38 +00:00
anselm@anselm1 d8688f7a4f added dmenu run 2007-12-22 12:20:20 +00:00
Anselm R. Garbe 09d0926bb9 Added tag 3.4 for changeset 9ab649b3b3e5 2007-10-25 20:26:17 +02:00
Anselm R. Garbe adc4ec02c0 adapted c99 for pedantic checks, even if those checks are somewhat broken 2007-10-10 18:57:51 +02:00
Anselm R. Garbe 8b2f132973 implemented strcasestr for dmenu (I call it cistrstr) for portability issues (cygwin has no strcasestr, oh dear) 2007-10-01 15:28:42 +02:00
Anselm R. Garbe 1c488e6dac fixed font definition 2007-10-01 11:44:25 +02:00
Anselm R. Garbe 03c546c6b3 fixed dmenu 2007-09-30 19:20:31 +02:00
Anselm R. Garbe fdc1dba7ce using saner defaults 2007-09-30 12:47:40 +02:00
Anselm R. Garbe 3439470a47 applied new color nuance 2007-09-27 18:55:05 +02:00
Anselm R. Garbe 6674bac1d3 applied my favorite color scheme 2007-09-26 19:15:47 +02:00
arg@suckless.org 72a8eb412f casting char to int when using tolower (thanks to Jukkas careful cosmetic checking!) 2007-09-24 15:04:31 +02:00
Anselm R. Garbe 975dfb4163 switching to white 2007-09-23 18:49:24 +02:00
Anselm R. Garbe 2e898a308f yet another cosmetic fix 2007-09-23 18:32:08 +02:00
Anselm R. Garbe 6514b07ad2 small cosmetic fix 2007-09-23 18:31:19 +02:00
Anselm R. Garbe 724fe3cf7f applied Michał Janeczek dmenu patch, made dmenu match case-insensitive by default, added -i command line option to enable ido matching, added Michał to Copyright holders 2007-09-23 18:26:41 +02:00
Anselm R. Garbe 70cb32b021 Added tag 3.3 for changeset 709df5a4bad7 2007-09-22 09:12:50 +02:00
arg@suckless.org 56f9e26b72 applied yiyus initfont fix 2007-09-19 17:33:35 +02:00
Anselm R. Garbe d094ebea96 reorganized 2007-09-17 20:53:14 +02:00
arg@suckless.org ccf4d7166f next version is 3.3 2007-09-17 09:13:21 +02:00
Anselm R. Garbe 06ae894434 micromizing dmenu step 1 2007-09-16 20:14:09 +02:00
Anselm R. Garbe b97783b07f fixed fallback 2007-09-15 20:28:20 +02:00
arg@f00b4r 11cb2e7dcc applied ido-matching to dmenu 2007-07-24 18:19:09 +02:00
Anselm R. Garbe 07239bbddd foooooo 2007-06-01 12:28:30 +02:00
Anselm R. Garbe 124bfd4a08 Added tag 3.2 for changeset e4c81a78ffba 2007-05-30 12:22:38 +02:00
20 changed files with 1663 additions and 828 deletions

No files matched your search

-33
View File
@@ -1,33 +0,0 @@
fcc8a282cb52c6a9343b461026b386825590cd31 0.1
656be0f47df545dfdd2e1e0663663b8b1b26f031 0.2
d352e9dc112ee96aa5cad961a0ed880ae9ce7276 0.3
7acf0dde1120542917bae12e0e42293f9d2cc899 0.4
4a0ecd881c4fc15de4a0bebd79308b064be020ef 0.5
25f679fb19686140a907684ffcb423b9e9d44b53 0.6
5fc20d7158bd16b4d5f8d1c25e177680b6d54252 0.7
409667a57221f7e50ba8b5248f638915cd61b366 0.8
d046c818ea467555cc338751c9bf3024609f1f12 0.9
9e11140d4cc3eecac3b0ab752f91528fd5e04be8 1.0
e8c1e9733752db12f2dbd1fa93c46f5806242ba9 1.1
bee7fe6d1189174d0204ca3195b83cdc1bb4f82e 1.2
2eb9997be51cb1b11a8900728ccc0904f9371157 1.3
df3fbb050004c544d14e43c36f6a94cca6ed4a69 1.4
e071fb045bd9e8574947acff7196360bc0270e68 1.5
dcc5427f99f51a978386a0dd770467cd911ac84b 1.6
58dbef4aef3d45c7a3da6945e53c9667c0f02d5b 1.7
3696d77aaf02f5d15728dde3b9e35abcaf291496 1.7.1
d3e6fa22ae45b38b1bdb0d813390365e5930360b 1.8
c7f5f4d543170f03d70468e98a3a0ec8d2c4161b 1.9
1fce5c464fcd870b9f024aa1853d5cf3a3eb371b 2.0
7656557298c954469a6a9564e6649b1fb5db663e 2.1
90f0e34e7f118c9ad3227a1606211ee825942b1c 2.2
b6e09682c8adcb6569656bee73c311f9ab457715 2.3
9e9036cbfb4b7306c6fb366249e81dc0e65bdfde 2.4
03e83e2788c83ddd63b45a667939d7ec783c98cb 2.4.1
1ca5d430524e838c52ede912533cb90108c5cd66 2.4.2
041143e9fc544c62edc58af52cae9ac5237e5945 2.5
775f761a5647a05038e091d1c99fc35d3034cd68 2.6
fbd9e9d63f202afe6834ccfdf890904f1897ec0b 2.7
dd3d02b07cac44fbafc074a361c1002cebe7aae4 2.8
59b3024854db49739c6d237fa9077f04a2da847a 3.0
8f0f917ac988164e1b4446236e3a6ab6cfcb8c67 3.1
+8 -2
View File
@@ -1,7 +1,13 @@
MIT/X Consortium License
© 2006-2007 Anselm R. Garbe <garbeam at gmail dot com>
© 2006-2007 Sander van Dijk <a dot h dot vandijk at gmail dot com>
© 2006-2014 Anselm R Garbe <anselm@garbe.us>
© 2010-2012 Connor Lane Smith <cls@lubutu.com>
© 2009 Gottox <gottox@s01.de>
© 2009 Markus Schnalke <meillo@marmaro.de>
© 2009 Evan Gates <evan.gates@gmail.com>
© 2006-2008 Sander van Dijk <a dot h dot vandijk at gmail dot com>
© 2006-2007 Michał Janeczek <janeczek at gmail dot com>
© 2014-2015 Hiltjo Posthuma <hiltjo@codemadness.org>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
+31 -13
View File
@@ -1,12 +1,12 @@
# dmenu - dynamic menu
# © 2006-2007 Anselm R. Garbe, Sander van Dijk
# See LICENSE file for copyright and license details.
include config.mk
SRC = draw.c main.c util.c
SRC = drw.c dmenu.c stest.c util.c
OBJ = ${SRC:.c=.o}
all: options dmenu
all: options dmenu stest
options:
@echo dmenu build options:
@@ -18,39 +18,57 @@ options:
@echo CC $<
@${CC} -c ${CFLAGS} $<
${OBJ}: dmenu.h config.mk
config.h:
@echo creating $@ from config.def.h
@cp config.def.h $@
dmenu: ${OBJ}
${OBJ}: arg.h config.h config.mk drw.h
dmenu: dmenu.o drw.o util.o
@echo CC -o $@
@${CC} -o $@ ${OBJ} ${LDFLAGS}
@${CC} -o $@ dmenu.o drw.o util.o ${LDFLAGS}
stest: stest.o
@echo CC -o $@
@${CC} -o $@ stest.o ${LDFLAGS}
clean:
@echo cleaning
@rm -f dmenu ${OBJ} dmenu-${VERSION}.tar.gz
@rm -f dmenu stest ${OBJ} dmenu-${VERSION}.tar.gz
dist: clean
@echo creating dist tarball
@mkdir -p dmenu-${VERSION}
@cp -R LICENSE Makefile README config.mk dmenu.1 dmenu.h dmenu_path ${SRC} 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
@echo installing executable file to ${DESTDIR}${PREFIX}/bin
@echo installing executables to ${DESTDIR}${PREFIX}/bin
@mkdir -p ${DESTDIR}${PREFIX}/bin
@cp -f dmenu dmenu_path ${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
@echo installing manual page to ${DESTDIR}${MANPREFIX}/man1
@chmod 755 ${DESTDIR}${PREFIX}/bin/dmenu_run
@chmod 755 ${DESTDIR}${PREFIX}/bin/stest
@echo installing manual pages to ${DESTDIR}${MANPREFIX}/man1
@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:
@echo removing executable file from ${DESTDIR}${PREFIX}/bin
@rm -f ${DESTDIR}${PREFIX}/bin/dmenu ${DESTDIR}${PREFIX}/bin/dmenu_path
@echo removing executables from ${DESTDIR}${PREFIX}/bin
@rm -f ${DESTDIR}${PREFIX}/bin/dmenu
@rm -f ${DESTDIR}${PREFIX}/bin/dmenu_path
@rm -f ${DESTDIR}${PREFIX}/bin/dmenu_run
@rm -f ${DESTDIR}${PREFIX}/bin/stest
@echo removing manual page from ${DESTDIR}${MANPREFIX}/man1
@rm -f ${DESTDIR}${MANPREFIX}/man1/dmenu.1
@rm -f ${DESTDIR}${MANPREFIX}/man1/stest.1
.PHONY: all options clean dist install uninstall
+3 -3
View File
@@ -1,6 +1,6 @@
dmenu - dynamic menu
====================
dmenu is a generic and efficient menu for X.
dmenu is an efficient dynamic menu for X.
Requirements
@@ -13,8 +13,8 @@ Installation
Edit config.mk to match your local setup (dmenu is installed into
the /usr/local namespace by default).
Afterwards enter the following command to build and install dmenu (if
necessary as root):
Afterwards enter the following command to build and install dmenu
(if necessary as root):
make clean install
+49
View File
@@ -0,0 +1,49 @@
/*
* Copy me if you can.
* by 20h
*/
#ifndef ARG_H__
#define ARG_H__
extern char *argv0;
/* use main(int argc, char *argv[]) */
#define ARGBEGIN for (argv0 = *argv, argv++, argc--;\
argv[0] && argv[0][1]\
&& argv[0][0] == '-';\
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
+17
View File
@@ -0,0 +1,17 @@
/* See LICENSE file for copyright and license details. */
/* Default settings; can be overriden by command line. */
static int topbar = 1; /* -b option; if 0, dmenu appears at bottom */
/* -fn option overrides fonts[0]; default X11 font or font set */
static const char *fonts[] = {
"monospace:size=10"
};
static const char *prompt = NULL; /* -p option; prompt to the elft of input field */
static const char *normbgcolor = "#222222"; /* -nb option; normal background */
static const char *normfgcolor = "#bbbbbb"; /* -nf option; normal foreground */
static const char *selbgcolor = "#005577"; /* -sb option; selected background */
static const char *selfgcolor = "#eeeeee"; /* -sf option; selected foreground */
static const char *outbgcolor = "#00ffff";
static const char *outfgcolor = "#000000";
/* -l option; if nonzero, dmenu uses vertical list with given number of lines */
static unsigned int lines = 0;
+15 -13
View File
@@ -1,7 +1,5 @@
# dmenu version
VERSION = 3.2
# Customize below to fit your system
VERSION = 4.6
# paths
PREFIX = /usr/local
@@ -10,20 +8,24 @@ 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. -I/usr/include -I${X11INC}
LIBS = -L/usr/lib -lc -L${X11LIB} -lX11
INCS = -I${X11INC} -I${FREETYPEINC}
LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS}
# flags
CFLAGS = -Os ${INCS} -DVERSION=\"${VERSION}\"
CPPFLAGS = -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_POSIX_C_SOURCE=200809L -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS}
LDFLAGS = -s ${LIBS}
#CFLAGS = -g -Wall -O2 ${INCS} -DVERSION=\"${VERSION}\"
#LDFLAGS = -g ${LIBS}
# Solaris
#CFLAGS = -fast ${INCS} -DVERSION=\"${VERSION}\"
#LDFLAGS = ${LIBS}
#CFLAGS += -xtarget=ultra
# compiler and linker
CC = cc
+152 -66
View File
@@ -4,91 +4,177 @@ dmenu \- dynamic menu
.SH SYNOPSIS
.B dmenu
.RB [ \-b ]
.RB [ \-fn " <font>"]
.RB [ \-nb " <color>"]
.RB [ \-nf " <color>"]
.RB [ \-p " <prompt>"]
.RB [ \-sb " <color>"]
.RB [ \-sf " <color>"]
.RB [ \-f ]
.RB [ \-i ]
.RB [ \-l
.RB [ \-m
.IR monitor ]
.IR lines ]
.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 [ \-v ]
.P
.BR dmenu_run " ..."
.SH DESCRIPTION
.SS Overview
dmenu is a generic menu for X, originally designed for
.BR dwm (1).
It manages huge amounts (up to 10.000 and more) of user defined menu items
efficiently.
.SS Options
.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
makes dmenu appear at the screen bottom (by default it appears at the screen top).
dmenu appears at the bottom of the screen.
.TP
.B \-fn <font>
defines the font.
.B \-f
dmenu grabs the keyboard before reading stdin. This is faster, but will lock up
X until stdin reaches end\-of\-file.
.TP
.B \-nb <color>
defines the normal background color (#RGB, #RRGGBB, and color names are supported).
.B \-i
dmenu matches menu items case insensitively.
.TP
.B \-nf <color>
defines the normal foreground color (#RGB, #RRGGBB, and color names are supported).
.BI \-l " lines"
dmenu lists items vertically, with the given number of lines.
.TP
.B \-p <prompt>
defines a prompt to be displayed before the input area.
.BI \-m " monitor"
dmenu is displayed on the monitor number supplied. Monitor numbers are starting
from 0.
.TP
.B \-sb <color>
defines the selected background color (#RGB, #RRGGBB, and color names are supported).
.BI \-p " prompt"
defines the prompt to be displayed to the left of the input field.
.TP
.B \-sf <color>
defines the selected foreground color (#RGB, #RRGGBB, and color names are supported).
.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 standard output, then exits.
prints version information to stdout, then exits.
.SH USAGE
dmenu reads a list of newline-separated items from standard input and creates a
menu. When the user selects an item or enters any text and presses Return, his/her
choice is printed to standard output and dmenu terminates.
.P
dmenu is completely controlled by the keyboard. The following keys are recognized:
dmenu is completely controlled by the keyboard. Items are selected using the
arrow keys, page up, page down, home, and end.
.TP
.B Any printable character
Appends the character to the text in the input field. This works as a filter:
only items containing this text will be displayed.
.TP
.B Left/Right (Mod1\-h/Mod1\-l)
Select the previous/next item.
.TP
.B PageUp/PageDown (Mod1\-k/Mod1\-j)
Select the first item of the previous/next 'page' of items.
.TP
.B Home/End (Mod1\-g/Mod1\-G)
Select the first/last item.
.TP
.B Tab (Control\-i)
.B Tab
Copy the selected item to the input field.
.TP
.B Return (Control\-j)
Confirm selection and quit (print the selected item to standard output). Returns
.B 0
on termination.
.B Return
Confirm selection. Prints the selected item to stdout and exits, returning
success.
.TP
.B Shift\-Return (Control\-Shift\-j)
Confirm selection and quit (print the text in the input field to standard output).
Returns
.B 0
on termination.
.B Ctrl-Return
Confirm selection. Prints the selected item to stdout and continues.
.TP
.B Escape (Control\-bracketleft)
Quit without selecting an item. Returns
.B 1
on termination.
.B Shift\-Return
Confirm input. Prints the input text to stdout and exits, returning success.
.TP
.B Backspace (Control\-h)
Remove a character from the input field.
.B Escape
Exit without selecting an item, returning failure.
.TP
.B Control\-u
Remove all characters from the input field.
C\-a
Home
.TP
.B Control\-w
Remove all characters of current word from the input field.
C\-b
Left
.TP
C\-c
Escape
.TP
C\-d
Delete
.TP
C\-e
End
.TP
C\-f
Right
.TP
C\-g
Escape
.TP
C\-h
Backspace
.TP
C\-i
Tab
.TP
C\-j
Return
.TP
C\-J
Shift-Return
.TP
C\-k
Delete line right
.TP
C\-m
Return
.TP
C\-M
Shift-Return
.TP
C\-n
Down
.TP
C\-p
Up
.TP
C\-u
Delete line left
.TP
C\-w
Delete word left
.TP
C\-y
Paste from primary X selection
.TP
C\-Y
Paste from X clipboard
.TP
M\-g
Home
.TP
M\-G
End
.TP
M\-h
Up
.TP
M\-j
Page down
.TP
M\-k
Page up
.TP
M\-l
Down
.SH SEE ALSO
.BR dwm (1),
.BR wmii (1) .
.IR dwm (1),
.IR stest (1)
+680
View File
@@ -0,0 +1,680 @@
/* 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 <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 "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 TEXTNW(X,N) (drw_font_getexts_width(drw->fonts[0], (X), (N)))
#define TEXTW(X) (drw_text(drw, 0, 0, 0, 0, (X), 0) + drw->fonts[0]->h)
/* enums */
enum { SchemeNorm, SchemeSel, SchemeOut, SchemeLast }; /* color schemes */
struct item {
char *text;
struct item *left, *right;
int out;
};
static char text[BUFSIZ] = "";
static int bh, mw, mh;
static int sw, sh; /* X display screen geometry width, height */
static int inputw, promptw;
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, win;
static XIC xic;
static ClrScheme scheme[SchemeLast];
static Drw *drw;
#include "config.h"
static int (*fstrncmp)(const char *, const char *, size_t) = strncmp;
static char *(*fstrstr)(const char *, const char *) = strstr;
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++) {
drw_clr_free(scheme[i].bg);
drw_clr_free(scheme[i].fg);
}
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 void
drawmenu(void)
{
int curpos;
struct item *item;
int x = 0, y = 0, h = bh, w;
drw_setscheme(drw, &scheme[SchemeNorm]);
drw_rect(drw, 0, 0, mw, mh, 1, 1, 1);
if (prompt && *prompt) {
drw_setscheme(drw, &scheme[SchemeSel]);
drw_text(drw, x, 0, promptw, bh, prompt, 0);
x += promptw;
}
/* draw input field */
w = (lines > 0 || !matches) ? mw - x : inputw;
drw_setscheme(drw, &scheme[SchemeNorm]);
drw_text(drw, x, 0, w, bh, text, 0);
if ((curpos = TEXTNW(text, cursor) + bh / 2 - 2) < w) {
drw_setscheme(drw, &scheme[SchemeNorm]);
drw_rect(drw, x + curpos + 2, 2, 1, bh - 4, 1, 1, 0);
}
if (lines > 0) {
/* draw vertical list */
w = mw - x;
for (item = curr; item != next; item = item->right) {
y += h;
if (item == sel)
drw_setscheme(drw, &scheme[SchemeSel]);
else if (item->out)
drw_setscheme(drw, &scheme[SchemeOut]);
else
drw_setscheme(drw, &scheme[SchemeNorm]);
drw_text(drw, x, y, w, bh, item->text, 0);
}
} 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, "<", 0);
}
for (item = curr; item != next; item = item->right) {
x += w;
w = MIN(TEXTW(item->text), mw - x - TEXTW(">"));
if (item == sel)
drw_setscheme(drw, &scheme[SchemeSel]);
else if (item->out)
drw_setscheme(drw, &scheme[SchemeOut]);
else
drw_setscheme(drw, &scheme[SchemeNorm]);
drw_text(drw, x, 0, w, bh, item->text, 0);
}
w = TEXTW(">");
x = mw - w;
if (next) {
drw_setscheme(drw, &scheme[SchemeNorm]);
drw_text(drw, x, 0, w, bh, ">", 0);
}
}
drw_map(drw, win, 0, 0, mw, mh);
}
static void
grabkeyboard(void)
{
struct timespec ts = { .tv_sec = 0, .tv_nsec = 1000000 };
int i;
/* 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\n");
}
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\n", tokn * sizeof *tokv);
len = tokc ? strlen(tokv[0]) : 0;
matches = lprefix = lsubstr = matchend = prefixend = substrend = NULL;
textsize = strlen(text);
for (item = items; item && item->text; item++) {
for (i = 0; i < tokc; i++)
if (!fstrstr(item->text, tokv[i]))
break;
if (i != tokc) /* not all tokens match */
continue;
/* exact matches go first, then prefixes, then substrings */
if (!tokc || !fstrncmp(text, item->text, textsize))
appenditem(item, &matches, &matchend);
else if (!fstrncmp(tokv[0], item->text, len))
appenditem(item, &lprefix, &prefixend);
else
appenditem(item, &lsubstr, &substrend);
}
if (lprefix) {
if (matches) {
matchend->right = lprefix;
lprefix->left = matchend;
} else
matches = lprefix;
matchend = prefixend;
}
if (lsubstr) {
if (matches) {
matchend->right = lsubstr;
lsubstr->left = matchend;
} else
matches = lsubstr;
matchend = substrend;
}
curr = sel = matches;
calcoffsets();
}
static void
insert(const char *str, ssize_t n)
{
if (strlen(text) + n > sizeof text - 1)
return;
/* move existing text out of the way, insert new text, and update cursor */
memmove(&text[cursor + n], &text[cursor], sizeof text - cursor - MAX(n, 0));
if (n > 0)
memcpy(&text[cursor], str, n);
cursor += n;
match();
}
static size_t
nextrune(int inc)
{
ssize_t n;
/* return location of next utf8 rune in the given direction (+1 or -1) */
for (n = cursor + inc; n + inc >= 0 && (text[n] & 0xc0) == 0x80; n += inc)
;
return n;
}
static void
keypress(XKeyEvent *ev)
{
char buf[32];
int len;
KeySym ksym = NoSymbol;
Status status;
len = XmbLookupString(xic, ev, buf, sizeof buf, &ksym, &status);
if (status == XBufferOverflow)
return;
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 && text[nextrune(-1)] == ' ')
insert(NULL, nextrune(-1) - cursor);
while (cursor > 0 && 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_Return:
case XK_KP_Enter:
break;
case XK_bracketleft:
cleanup();
exit(1);
default:
return;
}
else if (ev->state & Mod1Mask)
switch(ksym) {
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:
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;
}
drawmenu();
}
static void
paste(void)
{
char *p, *q;
int di;
unsigned long dl;
Atom da;
/* we have been given the current selection, now insert it into input */
XGetWindowProperty(dpy, win, utf8, 0, (sizeof text / 4) + 1, False,
utf8, &da, &di, &dl, &dl, (unsigned char **)&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, *maxstr = NULL;
size_t i, max = 0, size = 0;
/* read each line from stdin and add it to the item list */
for (i = 0; fgets(buf, sizeof buf, stdin); i++) {
if (i + 1 >= size / sizeof *items)
if (!(items = realloc(items, (size += BUFSIZ))))
die("cannot realloc %u bytes:", size);
if ((p = strchr(buf, '\n')))
*p = '\0';
if (!(items[i].text = strdup(buf)))
die("cannot strdup %u bytes:", strlen(buf) + 1);
items[i].out = 0;
if (strlen(items[i].text) > max)
max = strlen(maxstr = items[i].text);
}
if (items)
items[i].text = NULL;
inputw = maxstr ? TEXTW(maxstr) : 0;
lines = MIN(lines, i);
}
static void
run(void)
{
XEvent ev;
while (!XNextEvent(dpy, &ev)) {
if (XFilterEvent(&ev, win))
continue;
switch(ev.type) {
case Expose:
if (ev.xexpose.count == 0)
drw_map(drw, win, 0, 0, mw, mh);
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;
XSetWindowAttributes swa;
XIM xim;
#ifdef XINERAMA
XineramaScreenInfo *info;
Window w, pw, dw, *dws;
XWindowAttributes wa;
int a, j, di, n, i = 0, area = 0;
unsigned int du;
#endif
/* init appearance */
scheme[SchemeNorm].bg = drw_clr_create(drw, normbgcolor);
scheme[SchemeNorm].fg = drw_clr_create(drw, normfgcolor);
scheme[SchemeSel].bg = drw_clr_create(drw, selbgcolor);
scheme[SchemeSel].fg = drw_clr_create(drw, selfgcolor);
scheme[SchemeOut].bg = drw_clr_create(drw, outbgcolor);
scheme[SchemeOut].fg = drw_clr_create(drw, outfgcolor);
clip = XInternAtom(dpy, "CLIPBOARD", False);
utf8 = XInternAtom(dpy, "UTF8_STRING", False);
/* calculate menu geometry */
bh = drw->fonts[0]->h + 2;
lines = MAX(lines, 0);
mh = (lines + 1) * bh;
#ifdef XINERAMA
if ((info = XineramaQueryScreens(dpy, &n))) {
XGetInputFocus(dpy, &w, &di);
if (mon != -1 && 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 == -1 && !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
{
x = 0;
y = topbar ? 0 : sh - mh;
mw = sw;
}
promptw = (prompt && *prompt) ? TEXTW(prompt) : 0;
inputw = MIN(inputw, mw/3);
match();
/* create menu window */
swa.override_redirect = True;
swa.background_pixel = scheme[SchemeNorm].bg->pix;
swa.event_mask = ExposureMask | KeyPressMask | VisibilityChangeMask;
win = XCreateWindow(dpy, root, x, y, mw, mh, 0,
DefaultDepth(dpy, screen), CopyFromParent,
DefaultVisual(dpy, screen),
CWOverrideRedirect | CWBackPixel | CWEventMask, &swa);
/* open input methods */
xim = XOpenIM(dpy, NULL, NULL, NULL);
xic = XCreateIC(xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
XNClientWindow, win, XNFocusWindow, win, NULL);
XMapRaised(dpy, win);
drw_resize(drw, mw, mh);
drawmenu();
}
static void
usage(void)
{
fputs("usage: dmenu [-b] [-f] [-i] [-l lines] [-p prompt] [-fn font] [-m monitor]\n"
" [-nb color] [-nf color] [-sb color] [-sf color] [-v]\n", stderr);
exit(1);
}
int
main(int argc, char *argv[])
{
int i, fast = 0;
for (i = 1; i < argc; i++)
/* these options take no arguments */
if (!strcmp(argv[i], "-v")) { /* prints version information */
puts("dmenu-"VERSION);
exit(0);
} else if (!strcmp(argv[i], "-b")) /* appears at the bottom of the screen */
topbar = 0;
else if (!strcmp(argv[i], "-f")) /* grabs keyboard before reading stdin */
fast = 1;
else if (!strcmp(argv[i], "-i")) { /* case-insensitive item matching */
fstrncmp = strncasecmp;
fstrstr = cistrstr;
} else if (i + 1 == argc)
usage();
/* these options take one argument */
else if (!strcmp(argv[i], "-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 */
normbgcolor = argv[++i];
else if (!strcmp(argv[i], "-nf")) /* normal foreground color */
normfgcolor = argv[++i];
else if (!strcmp(argv[i], "-sb")) /* selected background color */
selbgcolor = argv[++i];
else if (!strcmp(argv[i], "-sf")) /* selected foreground color */
selfgcolor = argv[++i];
else
usage();
if (!setlocale(LC_CTYPE, "") || !XSupportsLocale())
fputs("warning: no locale support\n", stderr);
if (!(dpy = XOpenDisplay(NULL)))
die("cannot open display\n");
screen = DefaultScreen(dpy);
root = RootWindow(dpy, screen);
sw = DisplayWidth(dpy, screen);
sh = DisplayHeight(dpy, screen);
drw = drw_create(dpy, screen, root, sw, sh);
drw_load_fonts(drw, fonts, LENGTH(fonts));
if (!drw->fontcount)
die("no fonts could be loaded.\n");
drw_setscheme(drw, &scheme[SchemeNorm]);
if (fast) {
grabkeyboard();
readstdin();
} else {
readstdin();
grabkeyboard();
}
setup();
run();
return 1; /* unreachable */
}
-41
View File
@@ -1,41 +0,0 @@
/* See LICENSE file for copyright and license details. */
#include <X11/Xlib.h>
#define FONT "-*-fixed-medium-r-normal-*-13-*-*-*-*-*-*-*"
#define NORMBGCOLOR "#eeeeee"
#define NORMFGCOLOR "#222222"
#define SELBGCOLOR "#006699"
#define SELFGCOLOR "#ffffff"
#define SPACE 30 /* px */
/* color */
enum { ColFG, ColBG, ColLast };
typedef struct {
int x, y, w, h;
unsigned long norm[ColLast];
unsigned long sel[ColLast];
Drawable drawable;
GC gc;
struct {
XFontStruct *xfont;
XFontSet set;
int ascent;
int descent;
int height;
} font;
} DC; /* draw context */
int screen;
Display *dpy;
DC dc; /* global drawing context */
/* draw.c */
void drawtext(const char *text, unsigned long col[ColLast]);
unsigned int textw(const char *text);
unsigned int textnw(const char *text, unsigned int len);
/* util.c */
void *emalloc(unsigned int size); /* allocates memory, exits on error */
void eprint(const char *errstr, ...); /* prints errstr and exits with 1 */
char *estrdup(const char *str); /* duplicates str, exits on allocation error */
Executable → Regular
+10 -23
View File
@@ -1,26 +1,13 @@
#!/bin/sh
CACHE=$HOME/.dmenu_cache
cachedir=${XDG_CACHE_HOME:-"$HOME/.cache"}
if [ -d "$cachedir" ]; then
cache=$cachedir/dmenu_run
else
cache=$HOME/.dmenu_cache # if no xdg dir, fall back to dotfile in ~
fi
IFS=:
uptodate() {
test ! -f $CACHE && return 1
for dir in $PATH
do
test $dir -nt $CACHE && return 1
done
return 0
}
if ! uptodate
then
for dir in $PATH
do
for file in "$dir"/*
do
test -x "$file" && echo "${file##*/}"
done
done | sort | uniq > $CACHE.$$
mv $CACHE.$$ $CACHE
if stest -dqr -n "$cache" $PATH; then
stest -flx $PATH | sort -u | tee "$cache"
else
cat "$cache"
fi
cat $CACHE
Executable
+2
View File
@@ -0,0 +1,2 @@
#!/bin/sh
dmenu_path | dmenu "$@" | ${SHELL:-"/bin/sh"} &
-61
View File
@@ -1,61 +0,0 @@
/* See LICENSE file for copyright and license details. */
#include "dmenu.h"
#include <string.h>
/* extern */
void
drawtext(const char *text, unsigned long col[ColLast]) {
int x, y, w, h;
static char buf[256];
unsigned int len, olen;
XRectangle r = { dc.x, dc.y, dc.w, dc.h };
XSetForeground(dpy, dc.gc, col[ColBG]);
XFillRectangles(dpy, dc.drawable, dc.gc, &r, 1);
if(!text)
return;
w = 0;
olen = len = strlen(text);
if(len >= sizeof buf)
len = sizeof buf - 1;
memcpy(buf, text, len);
buf[len] = 0;
h = dc.font.ascent + dc.font.descent;
y = dc.y + (dc.h / 2) - (h / 2) + dc.font.ascent;
x = dc.x + (h / 2);
/* shorten text if necessary */
while(len && (w = textnw(buf, len)) > dc.w - h)
buf[--len] = 0;
if(len < olen) {
if(len > 1)
buf[len - 1] = '.';
if(len > 2)
buf[len - 2] = '.';
if(len > 3)
buf[len - 3] = '.';
}
if(w > dc.w)
return; /* too long */
XSetForeground(dpy, dc.gc, col[ColFG]);
if(dc.font.set)
XmbDrawString(dpy, dc.drawable, dc.font.set, dc.gc, x, y, buf, len);
else
XDrawString(dpy, dc.drawable, dc.gc, x, y, buf, len);
}
unsigned int
textw(const char *text) {
return textnw(text, strlen(text)) + dc.font.height;
}
unsigned int
textnw(const char *text, unsigned int len) {
XRectangle r;
if(dc.font.set) {
XmbTextExtents(dc.font.set, text, len, NULL, &r);
return r.width;
}
return XTextWidth(dc.font.xfont, text, len);
}
+398
View File
@@ -0,0 +1,398 @@
/* 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;
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);
drw->fontcount = 0;
XSetLineAttributes(dpy, drw->gc, 1, LineSolid, CapButt, JoinMiter);
return drw;
}
void
drw_resize(Drw *drw, unsigned int w, unsigned int h)
{
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)
{
size_t i;
for (i = 0; i < drw->fontcount; i++)
drw_font_free(drw->fonts[i]);
XFreePixmap(drw->dpy, drw->drawable);
XFreeGC(drw->dpy, drw->gc);
free(drw);
}
/* This function is an implementation detail. Library users should use
* drw_font_create instead.
*/
static Fnt *
drw_font_xcreate(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 same
* 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: '%s'\n", fontname);
return NULL;
}
if (!(pattern = FcNameParse((FcChar8 *) fontname))) {
fprintf(stderr, "error, cannot load font: '%s'\n", fontname);
XftFontClose(drw->dpy, xfont);
return NULL;
}
} else if (fontpattern) {
if (!(xfont = XftFontOpenPattern(drw->dpy, fontpattern))) {
fprintf(stderr, "error, cannot load font pattern.\n");
return NULL;
}
} else {
die("no font specified.\n");
}
font = ecalloc(1, sizeof(Fnt));
font->xfont = xfont;
font->pattern = pattern;
font->ascent = xfont->ascent;
font->descent = xfont->descent;
font->h = font->ascent + font->descent;
font->dpy = drw->dpy;
return font;
}
Fnt*
drw_font_create(Drw *drw, const char *fontname)
{
return drw_font_xcreate(drw, fontname, NULL);
}
void
drw_load_fonts(Drw* drw, const char *fonts[], size_t fontcount)
{
size_t i;
Fnt *font;
for (i = 0; i < fontcount; i++) {
if (drw->fontcount >= DRW_FONT_CACHE_SIZE) {
die("Font cache exhausted.\n");
} else if ((font = drw_font_xcreate(drw, fonts[i], NULL))) {
drw->fonts[drw->fontcount++] = font;
}
}
}
void
drw_font_free(Fnt *font)
{
if (!font)
return;
if (font->pattern)
FcPatternDestroy(font->pattern);
XftFontClose(font->dpy, font->xfont);
free(font);
}
Clr *
drw_clr_create(Drw *drw, const char *clrname)
{
Clr *clr;
clr = ecalloc(1, sizeof(Clr));
if (!XftColorAllocName(drw->dpy, DefaultVisual(drw->dpy, drw->screen),
DefaultColormap(drw->dpy, drw->screen),
clrname, &clr->rgb))
die("error, cannot allocate color '%s'\n", clrname);
clr->pix = clr->rgb.pixel;
return clr;
}
void
drw_clr_free(Clr *clr)
{
free(clr);
}
void
drw_setscheme(Drw *drw, ClrScheme *scheme)
{
drw->scheme = scheme;
}
void
drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int empty, int invert)
{
if (!drw->scheme)
return;
XSetForeground(drw->dpy, drw->gc, invert ? drw->scheme->bg->pix : drw->scheme->fg->pix);
if (filled)
XFillRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w + 1, h + 1);
else if (empty)
XDrawRectangle(drw->dpy, drw->drawable, drw->gc, x, y, w, h);
}
int
drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, const char *text, int invert)
{
char buf[1024];
int tx, ty, th;
Extnts tex;
XftDraw *d = NULL;
Fnt *curfont, *nextfont;
size_t i, len;
int utf8strlen, utf8charlen, render;
long utf8codepoint = 0;
const char *utf8str;
FcCharSet *fccharset;
FcPattern *fcpattern;
FcPattern *match;
XftResult result;
int charexists = 0;
if (!drw->scheme || !drw->fontcount)
return 0;
if (!(render = x || y || w || h)) {
w = ~w;
} else {
XSetForeground(drw->dpy, drw->gc, invert ?
drw->scheme->fg->pix : drw->scheme->bg->pix);
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));
}
curfont = drw->fonts[0];
while (1) {
utf8strlen = 0;
utf8str = text;
nextfont = NULL;
while (*text) {
utf8charlen = utf8decode(text, &utf8codepoint, UTF_SIZ);
for (i = 0; i < drw->fontcount; i++) {
charexists = charexists || XftCharExists(drw->dpy, drw->fonts[i]->xfont, utf8codepoint);
if (charexists) {
if (drw->fonts[i] == curfont) {
utf8strlen += utf8charlen;
text += utf8charlen;
} else {
nextfont = drw->fonts[i];
}
break;
}
}
if (!charexists || (nextfont && nextfont != curfont))
break;
else
charexists = 0;
}
if (utf8strlen) {
drw_font_getexts(curfont, utf8str, utf8strlen, &tex);
/* shorten text if necessary */
for (len = MIN(utf8strlen, (sizeof buf) - 1); len && (tex.w > w - drw->fonts[0]->h || w < drw->fonts[0]->h); len--)
drw_font_getexts(curfont, utf8str, len, &tex);
if (len) {
memcpy(buf, utf8str, len);
buf[len] = '\0';
if (len < utf8strlen)
for (i = len; i && i > len - 3; buf[--i] = '.');
if (render) {
th = curfont->ascent + curfont->descent;
ty = y + (h / 2) - (th / 2) + curfont->ascent;
tx = x + (h / 2);
XftDrawStringUtf8(d, invert ? &drw->scheme->bg->rgb : &drw->scheme->fg->rgb, curfont->xfont, tx, ty, (XftChar8 *)buf, len);
}
x += tex.w;
w -= tex.w;
}
}
if (!*text) {
break;
} else if (nextfont) {
charexists = 0;
curfont = nextfont;
} else {
/* Regardless of whether or not a fallback font is found, the
* character must be drawn.
*/
charexists = 1;
if (drw->fontcount >= DRW_FONT_CACHE_SIZE)
continue;
fccharset = FcCharSetCreate();
FcCharSetAddChar(fccharset, utf8codepoint);
if (!drw->fonts[0]->pattern) {
/* Refer to the comment in drw_font_xcreate for more
* information. */
die("the first font in the cache must be loaded from a font string.\n");
}
fcpattern = FcPatternDuplicate(drw->fonts[0]->pattern);
FcPatternAddCharSet(fcpattern, FC_CHARSET, fccharset);
FcPatternAddBool(fcpattern, FC_SCALABLE, FcTrue);
FcConfigSubstitute(NULL, fcpattern, FcMatchPattern);
FcDefaultSubstitute(fcpattern);
match = XftFontMatch(drw->dpy, drw->screen, fcpattern, &result);
FcCharSetDestroy(fccharset);
FcPatternDestroy(fcpattern);
if (match) {
curfont = drw_font_xcreate(drw, NULL, match);
if (curfont && XftCharExists(drw->dpy, curfont->xfont, utf8codepoint)) {
drw->fonts[drw->fontcount++] = curfont;
} else {
drw_font_free(curfont);
curfont = drw->fonts[0];
}
}
}
}
if (d)
XftDrawDestroy(d);
return x;
}
void
drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h)
{
XCopyArea(drw->dpy, drw->drawable, win, drw->gc, x, y, w, h, x, y);
XSync(drw->dpy, False);
}
void
drw_font_getexts(Fnt *font, const char *text, unsigned int len, Extnts *tex)
{
XGlyphInfo ext;
XftTextExtentsUtf8(font->dpy, font->xfont, (XftChar8 *)text, len, &ext);
tex->h = font->h;
tex->w = ext.xOff;
}
unsigned int
drw_font_getexts_width(Fnt *font, const char *text, unsigned int len)
{
Extnts tex;
drw_font_getexts(font, text, len, &tex);
return tex.w;
}
Cur *
drw_cur_create(Drw *drw, int shape)
{
Cur *cur;
cur = ecalloc(1, sizeof(Cur));
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);
}
+74
View File
@@ -0,0 +1,74 @@
/* See LICENSE file for copyright and license details. */
#define DRW_FONT_CACHE_SIZE 32
typedef struct {
unsigned long pix;
XftColor rgb;
} Clr;
typedef struct {
Cursor cursor;
} Cur;
typedef struct {
Display *dpy;
int ascent;
int descent;
unsigned int h;
XftFont *xfont;
FcPattern *pattern;
} Fnt;
typedef struct {
Clr *fg;
Clr *bg;
Clr *border;
} ClrScheme;
typedef struct {
unsigned int w, h;
Display *dpy;
int screen;
Window root;
Drawable drawable;
GC gc;
ClrScheme *scheme;
size_t fontcount;
Fnt *fonts[DRW_FONT_CACHE_SIZE];
} Drw;
typedef struct {
unsigned int w;
unsigned int h;
} Extnts;
/* Drawable abstraction */
Drw *drw_create(Display *, int, Window, unsigned int, unsigned int);
void drw_resize(Drw *, unsigned int, unsigned int);
void drw_free(Drw *);
/* Fnt abstraction */
Fnt *drw_font_create(Drw *, const char *);
void drw_load_fonts(Drw *, const char *[], size_t);
void drw_font_free(Fnt *);
void drw_font_getexts(Fnt *, const char *, unsigned int, Extnts *);
unsigned int drw_font_getexts_width(Fnt *, const char *, unsigned int);
/* Colour abstraction */
Clr *drw_clr_create(Drw *, const char *);
void drw_clr_free(Clr *);
/* Cursor abstraction */
Cur *drw_cur_create(Drw *, int);
void drw_cur_free(Drw *, Cur *);
/* Drawing context manipulation */
void drw_setfont(Drw *, Fnt *);
void drw_setscheme(Drw *, ClrScheme *);
/* Drawing functions */
void drw_rect(Drw *, int, int, unsigned int, unsigned int, int, int, int);
int drw_text(Drw *, int, int, unsigned int, unsigned int, const char *, int);
/* Map functions */
void drw_map(Drw *, Window, int, int, unsigned int, unsigned int);
-555
View File
@@ -1,555 +0,0 @@
/* See LICENSE file for copyright and license details. */
#include "dmenu.h"
#include <ctype.h>
#include <locale.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#define CLEANMASK(mask) (mask & ~(numlockmask | LockMask))
typedef struct Item Item;
struct Item {
Item *next; /* traverses all items */
Item *left, *right; /* traverses items matching current search pattern */
char *text;
};
/* static */
static char text[4096];
static char *prompt = NULL;
static int mw, mh;
static int ret = 0;
static int nitem = 0;
static unsigned int cmdw = 0;
static unsigned int promptw = 0;
static unsigned int numlockmask = 0;
static Bool running = True;
static Item *allitems = NULL; /* first of all items */
static Item *item = NULL; /* first of pattern matching items */
static Item *sel = NULL;
static Item *next = NULL;
static Item *prev = NULL;
static Item *curr = NULL;
static Window root;
static Window win;
static void
calcoffsets(void) {
unsigned int tw, w;
if(!curr)
return;
w = promptw + cmdw + 2 * SPACE;
for(next = curr; next; next=next->right) {
tw = textw(next->text);
if(tw > mw / 3)
tw = mw / 3;
w += tw;
if(w > mw)
break;
}
w = promptw + cmdw + 2 * SPACE;
for(prev = curr; prev && prev->left; prev=prev->left) {
tw = textw(prev->left->text);
if(tw > mw / 3)
tw = mw / 3;
w += tw;
if(w > mw)
break;
}
}
static void
drawmenu(void) {
Item *i;
dc.x = 0;
dc.y = 0;
dc.w = mw;
dc.h = mh;
drawtext(NULL, dc.norm);
/* print prompt? */
if(promptw) {
dc.w = promptw;
drawtext(prompt, dc.sel);
}
dc.x += promptw;
dc.w = mw - promptw;
/* print command */
if(cmdw && item)
dc.w = cmdw;
drawtext(text[0] ? text : NULL, dc.norm);
dc.x += cmdw;
if(curr) {
dc.w = SPACE;
drawtext((curr && curr->left) ? "<" : NULL, dc.norm);
dc.x += dc.w;
/* determine maximum items */
for(i = curr; i != next; i=i->right) {
dc.w = textw(i->text);
if(dc.w > mw / 3)
dc.w = mw / 3;
drawtext(i->text, (sel == i) ? dc.sel : dc.norm);
dc.x += dc.w;
}
dc.x = mw - SPACE;
dc.w = SPACE;
drawtext(next ? ">" : NULL, dc.norm);
}
XCopyArea(dpy, dc.drawable, win, dc.gc, 0, 0, mw, mh, 0, 0);
XFlush(dpy);
}
static Bool
grabkeyboard(void) {
unsigned int len;
for(len = 1000; len; len--) {
if(XGrabKeyboard(dpy, root, True, GrabModeAsync, GrabModeAsync, CurrentTime)
== GrabSuccess)
break;
usleep(1000);
}
return len > 0;
}
static unsigned long
initcolor(const char *colstr) {
Colormap cmap = DefaultColormap(dpy, screen);
XColor color;
if(!XAllocNamedColor(dpy, cmap, colstr, &color, &color))
eprint("error, cannot allocate color '%s'\n", colstr);
return color.pixel;
}
static void
initfont(const char *fontstr) {
char *def, **missing;
int i, n;
if(!fontstr || fontstr[0] == '\0')
eprint("error, cannot load font: '%s'\n", fontstr);
missing = NULL;
if(dc.font.set)
XFreeFontSet(dpy, dc.font.set);
dc.font.set = XCreateFontSet(dpy, fontstr, &missing, &n, &def);
if(missing)
XFreeStringList(missing);
if(dc.font.set) {
XFontSetExtents *font_extents;
XFontStruct **xfonts;
char **font_names;
dc.font.ascent = dc.font.descent = 0;
font_extents = XExtentsOfFontSet(dc.font.set);
n = XFontsOfFontSet(dc.font.set, &xfonts, &font_names);
for(i = 0, dc.font.ascent = 0, dc.font.descent = 0; i < n; i++) {
if(dc.font.ascent < (*xfonts)->ascent)
dc.font.ascent = (*xfonts)->ascent;
if(dc.font.descent < (*xfonts)->descent)
dc.font.descent = (*xfonts)->descent;
xfonts++;
}
}
else {
if(dc.font.xfont)
XFreeFont(dpy, dc.font.xfont);
dc.font.xfont = NULL;
if(!(dc.font.xfont = XLoadQueryFont(dpy, fontstr)))
eprint("error, cannot load font: '%s'\n", fontstr);
dc.font.ascent = dc.font.xfont->ascent;
dc.font.descent = dc.font.xfont->descent;
}
dc.font.height = dc.font.ascent + dc.font.descent;
}
static void
match(char *pattern) {
unsigned int plen;
Item *i, *j;
if(!pattern)
return;
plen = strlen(pattern);
item = j = NULL;
nitem = 0;
for(i = allitems; i; i=i->next)
if(!plen || !strncmp(pattern, i->text, plen)) {
if(!j)
item = i;
else
j->right = i;
i->left = j;
i->right = NULL;
j = i;
nitem++;
}
for(i = allitems; i; i=i->next)
if(plen && strncmp(pattern, i->text, plen)
&& strstr(i->text, pattern)) {
if(!j)
item = i;
else
j->right = i;
i->left = j;
i->right = NULL;
j = i;
nitem++;
}
curr = prev = next = sel = item;
calcoffsets();
}
static void
kpress(XKeyEvent * e) {
char buf[32];
int i, num;
unsigned int len;
KeySym ksym;
len = strlen(text);
buf[0] = 0;
num = XLookupString(e, 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))
return;
/* first check if a control mask is omitted */
if(e->state & ControlMask) {
switch (ksym) {
default: /* ignore other control sequences */
return;
case XK_bracketleft:
ksym = XK_Escape;
break;
case XK_h:
case XK_H:
ksym = XK_BackSpace;
break;
case XK_i:
case XK_I:
ksym = XK_Tab;
break;
case XK_j:
case XK_J:
ksym = XK_Return;
break;
case XK_u:
case XK_U:
text[0] = 0;
match(text);
drawmenu();
return;
case XK_w:
case XK_W:
if(len) {
i = len - 1;
while(i >= 0 && text[i] == ' ')
text[i--] = 0;
while(i >= 0 && text[i] != ' ')
text[i--] = 0;
match(text);
drawmenu();
}
return;
}
}
if(CLEANMASK(e->state) & Mod1Mask) {
switch(ksym) {
default: return;
case XK_h:
ksym = XK_Left;
break;
case XK_l:
ksym = XK_Right;
break;
case XK_j:
ksym = XK_Next;
break;
case XK_k:
ksym = XK_Prior;
break;
case XK_g:
ksym = XK_Home;
break;
case XK_G:
ksym = XK_End;
break;
}
}
switch(ksym) {
default:
if(num && !iscntrl((int) buf[0])) {
buf[num] = 0;
if(len > 0)
strncat(text, buf, sizeof text);
else
strncpy(text, buf, sizeof text);
match(text);
}
break;
case XK_BackSpace:
if(len) {
text[--len] = 0;
match(text);
}
break;
case XK_End:
if(!item)
return;
while(next) {
sel = curr = next;
calcoffsets();
}
while(sel && sel->right)
sel = sel->right;
break;
case XK_Escape:
ret = 1;
running = False;
break;
case XK_Home:
if(!item)
return;
sel = curr = item;
calcoffsets();
break;
case XK_Left:
if(!(sel && sel->left))
return;
sel=sel->left;
if(sel->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:
if((e->state & ShiftMask) && text)
fprintf(stdout, "%s", text);
else if(sel)
fprintf(stdout, "%s", sel->text);
else if(text)
fprintf(stdout, "%s", text);
fflush(stdout);
running = False;
break;
case XK_Right:
if(!(sel && sel->right))
return;
sel=sel->right;
if(sel == next) {
curr = next;
calcoffsets();
}
break;
case XK_Tab:
if(!sel)
return;
strncpy(text, sel->text, sizeof text);
match(text);
break;
}
drawmenu();
}
static char *
readstdin(void) {
static char *maxname = NULL;
char *p, buf[1024];
unsigned int len = 0, max = 0;
Item *i, *new;
i = 0;
while(fgets(buf, sizeof buf, stdin)) {
len = strlen(buf);
if (buf[len - 1] == '\n')
buf[len - 1] = 0;
p = estrdup(buf);
if(max < len) {
maxname = p;
max = len;
}
new = emalloc(sizeof(Item));
new->next = new->left = new->right = NULL;
new->text = p;
if(!i)
allitems = new;
else
i->next = new;
i = new;
}
return maxname;
}
static void
usage(void) {
eprint("usage: dmenu [-b] [-fn <font>] [-nb <color>] [-nf <color>]\n"
" [-p <prompt>] [-sb <color>] [-sf <color>] [-v]\n");
}
/* extern */
int screen;
Display *dpy;
DC dc = {0};
int
main(int argc, char *argv[]) {
Bool bottom = False;
char *font = FONT;
char *maxname;
char *normbg = NORMBGCOLOR;
char *normfg = NORMFGCOLOR;
char *selbg = SELBGCOLOR;
char *selfg = SELFGCOLOR;
int i, j;
Item *itm;
XEvent ev;
XModifierKeymap *modmap;
XSetWindowAttributes wa;
/* command line args */
for(i = 1; i < argc; i++)
if(!strcmp(argv[i], "-b")) {
bottom = True;
}
else if(!strcmp(argv[i], "-fn")) {
if(++i < argc) font = argv[i];
}
else if(!strcmp(argv[i], "-nb")) {
if(++i < argc) normbg = argv[i];
}
else if(!strcmp(argv[i], "-nf")) {
if(++i < argc) normfg = argv[i];
}
else if(!strcmp(argv[i], "-p")) {
if(++i < argc) prompt = argv[i];
}
else if(!strcmp(argv[i], "-sb")) {
if(++i < argc) selbg = argv[i];
}
else if(!strcmp(argv[i], "-sf")) {
if(++i < argc) selfg = argv[i];
}
else if(!strcmp(argv[i], "-v"))
eprint("dmenu-"VERSION", © 2006-2007 Anselm R. Garbe, Sander van Dijk\n");
else
usage();
setlocale(LC_CTYPE, "");
dpy = XOpenDisplay(0);
if(!dpy)
eprint("dmenu: cannot open display\n");
screen = DefaultScreen(dpy);
root = RootWindow(dpy, screen);
if(isatty(STDIN_FILENO)) {
maxname = readstdin();
running = grabkeyboard();
}
else { /* prevent keypress loss */
running = grabkeyboard();
maxname = readstdin();
}
/* init modifier map */
modmap = XGetModifierMapping(dpy);
for (i = 0; i < 8; i++) {
for (j = 0; j < modmap->max_keypermod; j++) {
if(modmap->modifiermap[i * modmap->max_keypermod + j]
== XKeysymToKeycode(dpy, XK_Num_Lock))
numlockmask = (1 << i);
}
}
XFreeModifiermap(modmap);
/* style */
dc.norm[ColBG] = initcolor(normbg);
dc.norm[ColFG] = initcolor(normfg);
dc.sel[ColBG] = initcolor(selbg);
dc.sel[ColFG] = initcolor(selfg);
initfont(font);
/* menu window */
wa.override_redirect = 1;
wa.background_pixmap = ParentRelative;
wa.event_mask = ExposureMask | ButtonPressMask | KeyPressMask;
mw = DisplayWidth(dpy, screen);
mh = dc.font.height + 2;
win = XCreateWindow(dpy, root, 0,
bottom ? DisplayHeight(dpy, screen) - mh : 0, mw, mh, 0,
DefaultDepth(dpy, screen), CopyFromParent,
DefaultVisual(dpy, screen),
CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa);
/* pixmap */
dc.drawable = XCreatePixmap(dpy, root, mw, mh, DefaultDepth(dpy, screen));
dc.gc = XCreateGC(dpy, root, 0, 0);
XSetLineAttributes(dpy, dc.gc, 1, LineSolid, CapButt, JoinMiter);
if(!dc.font.set)
XSetFont(dpy, dc.gc, dc.font.xfont->fid);
if(maxname)
cmdw = textw(maxname);
if(cmdw > mw / 3)
cmdw = mw / 3;
if(prompt)
promptw = textw(prompt);
if(promptw > mw / 5)
promptw = mw / 5;
text[0] = 0;
match(text);
XMapRaised(dpy, win);
drawmenu();
XSync(dpy, False);
/* main event loop */
while(running && !XNextEvent(dpy, &ev))
switch (ev.type) {
default: /* ignore all crap */
break;
case KeyPress:
kpress(&ev.xkey);
break;
case Expose:
if(ev.xexpose.count == 0)
drawmenu();
break;
}
/* cleanup */
while(allitems) {
itm = allitems->next;
free(allitems->text);
free(allitems);
allitems = itm;
}
if(dc.font.set)
XFreeFontSet(dpy, dc.font.set);
else
XFreeFont(dpy, dc.font.xfont);
XFreePixmap(dpy, dc.drawable);
XFreeGC(dpy, dc.gc);
XDestroyWindow(dpy, win);
XUngrabKeyboard(dpy, CurrentTime);
XCloseDisplay(dpy);
return ret;
}
+90
View File
@@ -0,0 +1,90 @@
.TH STEST 1 dmenu\-VERSION
.SH NAME
stest \- filter a list of files by properties
.SH SYNOPSIS
.B stest
.RB [ -abcdefghlpqrsuwx ]
.RB [ -n
.IR file ]
.RB [ -o
.IR file ]
.RI [ file ...]
.SH DESCRIPTION
.B stest
takes a list of files and filters by the files' properties, analogous to
.IR test (1).
Files which pass all tests are printed to stdout. If no files are given, stest
reads files from stdin.
.SH OPTIONS
.TP
.B \-a
Test hidden files.
.TP
.B \-b
Test that files are block specials.
.TP
.B \-c
Test that files are character specials.
.TP
.B \-d
Test that files are directories.
.TP
.B \-e
Test that files exist.
.TP
.B \-f
Test that files are regular files.
.TP
.B \-g
Test that files have their set-group-ID flag set.
.TP
.B \-h
Test that files are symbolic links.
.TP
.B \-l
Test the contents of a directory given as an argument.
.TP
.BI \-n " file"
Test that files are newer than
.IR file .
.TP
.BI \-o " file"
Test that files are older than
.IR file .
.TP
.B \-p
Test that files are named pipes.
.TP
.B \-q
No files are printed, only the exit status is returned.
.TP
.B \-r
Test that files are readable.
.TP
.B \-s
Test that files are not empty.
.TP
.B \-u
Test that files have their set-user-ID flag set.
.TP
.B \-v
Invert the sense of tests, only failing files pass.
.TP
.B \-w
Test that files are writable.
.TP
.B \-x
Test that files are executable.
.SH EXIT STATUS
.TP
.B 0
At least one file passed all tests.
.TP
.B 1
No files passed all tests.
.TP
.B 2
An error occurred.
.SH SEE ALSO
.IR dmenu (1),
.IR test (1)
+109
View File
@@ -0,0 +1,109 @@
/* See LICENSE file for copyright and license details. */
#include <sys/stat.h>
#include <dirent.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "arg.h"
char *argv0;
#define FLAG(x) (flag[(x)-'a'])
static void test(const char *, const char *);
static void usage(void);
static int match = 0;
static int flag[26];
static struct stat old, new;
static void
test(const char *path, const char *name)
{
struct stat st, ln;
if ((!stat(path, &st) && (FLAG('a') || name[0] != '.') /* hidden files */
&& (!FLAG('b') || S_ISBLK(st.st_mode)) /* block special */
&& (!FLAG('c') || S_ISCHR(st.st_mode)) /* character special */
&& (!FLAG('d') || S_ISDIR(st.st_mode)) /* directory */
&& (!FLAG('e') || access(path, F_OK) == 0) /* exists */
&& (!FLAG('f') || S_ISREG(st.st_mode)) /* regular file */
&& (!FLAG('g') || st.st_mode & S_ISGID) /* set-group-id flag */
&& (!FLAG('h') || (!lstat(path, &ln) && S_ISLNK(ln.st_mode))) /* symbolic link */
&& (!FLAG('n') || st.st_mtime > new.st_mtime) /* newer than file */
&& (!FLAG('o') || st.st_mtime < old.st_mtime) /* older than file */
&& (!FLAG('p') || S_ISFIFO(st.st_mode)) /* named pipe */
&& (!FLAG('r') || access(path, R_OK) == 0) /* readable */
&& (!FLAG('s') || st.st_size > 0) /* not empty */
&& (!FLAG('u') || st.st_mode & S_ISUID) /* set-user-id flag */
&& (!FLAG('w') || access(path, W_OK) == 0) /* writable */
&& (!FLAG('x') || access(path, X_OK) == 0)) != FLAG('v')) { /* executable */
if (FLAG('q'))
exit(0);
match = 1;
puts(name);
}
}
static void
usage(void)
{
fprintf(stderr, "usage: %s [-abcdefghlpqrsuvwx] "
"[-n file] [-o file] [file...]\n", argv0);
exit(2); /* like test(1) return > 1 on error */
}
int
main(int argc, char *argv[])
{
struct dirent *d;
char path[PATH_MAX], *line = NULL, *file;
size_t linesiz = 0;
ssize_t n;
DIR *dir;
int r;
ARGBEGIN {
case 'n': /* newer than file */
case 'o': /* older than file */
file = EARGF(usage());
if (!(FLAG(ARGC()) = !stat(file, (ARGC() == 'n' ? &new : &old))))
perror(file);
break;
default:
/* miscellaneous operators */
if (strchr("abcdefghlpqrsuvwx", ARGC()))
FLAG(ARGC()) = 1;
else
usage(); /* unknown flag */
} ARGEND;
if (!argc) {
/* read list from stdin */
while ((n = getline(&line, &linesiz, stdin)) > 0) {
if (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;
}
+17 -18
View File
@@ -1,34 +1,33 @@
/* See LICENSE file for copyright and license details. */
#include "dmenu.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void *
emalloc(unsigned int size) {
void *res = malloc(size);
#include "util.h"
if(!res)
eprint("fatal: could not malloc() %u bytes\n", size);
return res;
void *
ecalloc(size_t nmemb, size_t size)
{
void *p;
if (!(p = calloc(nmemb, size)))
perror(NULL);
return p;
}
void
eprint(const char *errstr, ...) {
die(const char *fmt, ...) {
va_list ap;
va_start(ap, errstr);
vfprintf(stderr, errstr, ap);
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
exit(EXIT_FAILURE);
}
char *
estrdup(const char *str) {
void *res = strdup(str);
if (fmt[0] && fmt[strlen(fmt)-1] == ':') {
fputc(' ', stderr);
perror(NULL);
}
if(!res)
eprint("fatal: could not malloc() %u bytes\n", strlen(str));
return res;
exit(1);
}
+8
View File
@@ -0,0 +1,8 @@
/* See LICENSE file for copyright and license details. */
#define MAX(A, B) ((A) > (B) ? (A) : (B))
#define MIN(A, B) ((A) < (B) ? (A) : (B))
#define BETWEEN(X, A, B) ((A) <= (X) && (X) <= (B))
void die(const char *errstr, ...);
void *ecalloc(size_t, size_t);