Hello all!
I didn't thought it was so easy to extend `dmenu` but it seems it
is. So will just to fill in the context of this patch: yesterday I've
asked on the mailing list if there is a `dmenu` like replacement for
xmessage. (See the archive at:
http://lists.suckless.org/dev/1011/6486.html ) And I've received a lot
of feedback for which I thank to the posters.
Unfortunately none of the tools did what I needed... I figured out
that I actually need `dmenu` to be able to display some text message
(explaining the user what the input was for -- like a help message),
and just behave normally by letting the user select an item from the
list. (I think of it as a `dialog` replacement.) (I want to use it to
allow the user to confirm the actions of a background daemon, and the
message is longer than a single line.)
Thus I've made the following modifications to `dmenu`, which I
hereby place in the public domain (in the hope that it is going to be
accepted by the `dmenu` team and incorporated in the tool), and for
which I want to receive comments.
In summary, I've added two new arguments:
* `-of message-file` which gives the path to a file that contains
the message to be displayed; (it can be a pipe, nomal file, etc.);
* `-ol message-lines` which should limit the number of lines displayed;
I've also refactored the `readstdin` function which I've made to
delegate work to the `readfile` function, because I reuse it inside
the newly created function `readmsgfile`. (I've been careful to keep
inside `readstdin` the `inputw` computation and thus it is not
influenced by the `readmsgfile` function.)
Then I've added three new global variables: `msgfile`, `msglines`,
and `msgitems`, plus I've updated the `drawmenu` function (just before
the prompt) to include the drawing of the message lines.
(I've also added a sanity check to the `main` function to check if
the number of lines isn't negative, or if `-ol` was specified but not
`-of`.)
So any thoughts?
Ciprian.
diff -r a79e4a9cb167 dmenu.1
--- a/dmenu.1 Sat Nov 20 09:25:08 2010 +0000
+++ b/dmenu.1 Wed Nov 24 20:59:28 2010 +0200
@@ -11,6 +11,10 @@
.IR monitor ]
.RB [ \-p
.IR prompt ]
+.RB [ \-of
+.IR message-file ]
+.RB [ \-ol
+.IR message-lines ]
.RB [ \-fn
.IR font ]
.RB [ \-nb
@@ -59,6 +63,12 @@
.BI \-p " prompt"
defines the prompt to be displayed to the left of the input field.
.TP
+.BI \-of " message-file"
+defines the file from which a message is going to be displayed before the prompt.
+.TP
+.BI \-ol " message-lines"
+defines the maximum number of lines of message to display before the prompt.
+.TP
.BI \-fn " font"
defines the font or font set used.
.TP
diff -r a79e4a9cb167 dmenu.c
--- a/dmenu.c Sat Nov 20 09:25:08 2010 +0000
+++ b/dmenu.c Wed Nov 24 20:59:28 2010 +0200
@@ -34,6 +34,8 @@
static size_t nextrune(int incr);
static void paste(void);
static void readstdin(void);
+static void readmsgfile(void);
+static void readfile(Item **items, int maxitems, FILE *stream);
static void run(void);
static void setup(void);
static void usage(void);
@@ -51,12 +53,15 @@
static const char *normfgcolor = "#000000";
static const char *selbgcolor = "#0066ff";
static const char *selfgcolor = "#ffffff";
+static const char *msgfile = NULL;
+static int msglines = 0;
static unsigned long normcol[ColLast];
static unsigned long selcol[ColLast];
static Atom utf8;
static Bool topbar = True;
static DC *dc;
static Item *items = NULL;
+static Item *msgitems = NULL;
static Item *matches, *sel;
static Item *prev, *curr, *next;
static Window root, win;
@@ -97,12 +102,21 @@
selbgcolor = argv[++i];
else if(!strcmp(argv[i], "-sf"))
selfgcolor = argv[++i];
+ else if(!strcmp(argv[i], "-ol"))
+ msglines = atoi(argv[++i]);
+ else if(!strcmp(argv[i], "-of"))
+ msgfile = argv[++i];
else
usage();
+ if((!msgfile && msglines!=0) || (lines < 0) || (monitor < -1) || (msglines < 0))
+ usage();
+
dc = initdc();
initfont(dc, font);
readstdin();
+ if(msgfile)
+ readmsgfile();
setup();
run();
@@ -147,6 +161,13 @@
dc->h = bh;
drawrect(dc, 0, 0, mw, mh, True, BG(dc, normcol));
+ if(msglines) {
+ dc->w = mw;
+ for(item = msgitems, curpos = 0; item && curpos < msglines; item = item->next, curpos++) {
+ drawtext(dc, item->text, selcol);
+ dc->y += dc->h;
+ }
+ }
if(prompt) {
dc->w = promptw;
drawtext(dc, prompt, selcol);
@@ -432,10 +453,34 @@
void
readstdin(void) {
+ Item *item;
+ readfile(&items, 0, stdin);
+ for(item = items; item; item = item->next)
+ inputw = MAX(inputw, textw(dc, item->text));
+}
+
+void
+readmsgfile(void) {
+ Item *item;
+ FILE *stream;
+ stream = fopen (msgfile, "r");
+ if (!stream)
+ eprintf("cannot open message file %s\n", msgfile);
+ readfile(&msgitems, msglines, stream);
+ fclose(stream);
+
+ msglines = 0;
+ for(item = msgitems; item; item = item->next)
+ msglines++;
+}
+
+void
+readfile(Item **items, int maxlines, FILE *stream) {
char buf[sizeof text], *p;
Item *item, **end;
+ int count;
- for(end = &items; fgets(buf, sizeof buf, stdin); *end = item, end = &item->next) {
+ for(end = items, count = 0; (!maxlines || count < maxlines) && fgets(buf, sizeof buf, stream); *end = item, end = &item->next, count++) {
if((p = strchr(buf, '\n')))
*p = '\0';
if(!(item = malloc(sizeof *item)))
@@ -443,7 +488,6 @@
if(!(item->text = strdup(buf)))
eprintf("cannot strdup %u bytes\n", strlen(buf)+1);
item->next = item->left = item->right = NULL;
- inputw = MAX(inputw, textw(dc, item->text));
}
}
@@ -492,7 +536,7 @@
/* menu geometry */
bh = dc->font.height + 2;
lines = MAX(lines, 0);
- mh = (lines + 1) * bh;
+ mh = (msglines + lines + 1) * bh;
#ifdef XINERAMA
if((info = XineramaQueryScreens(dc->dpy, &n))) {
int i, di;
@@ -536,7 +580,8 @@
void
usage(void) {
- fputs("usage: dmenu [-b] [-i] [-l lines] [-m monitor] [-p prompt] [-fn font]\n"
+ fputs("usage: dmenu [-b] [-i] [-l lines] [-m monitor] [-p prompt]\n"
+ " [-of message-file] [-ol message-lines] [-fn font]\n"
" [-nb color] [-nf color] [-sb color] [-sf color] [-v]\n", stderr);
exit(EXIT_FAILURE);
}