You are not logged in.

#1 2011-08-20 10:02:40

bloom
Member
Registered: 2010-08-18
Posts: 749
Website

An x, y, w patch for dmenu

This patch provide the necessary options to achieve a precise placement of the dmenu window.
It also added an option to hide the matching items when the search string is empty.

diff -u dmenu-4.4/dmenu.1 dmenu/dmenu.1
--- dmenu-4.4/dmenu.1	2011-07-19 22:31:28.000000000 +0200
+++ dmenu/dmenu.1	2011-08-06 23:18:20.000000000 +0200
@@ -41,6 +41,9 @@
 .B \-b
 dmenu appears at the bottom of the screen.
 .TP
+.B \-q
+dmenu will not show any items if the search string is empty.
+.TP
 .B \-f
 dmenu grabs the keyboard before reading stdin.  This is faster, but may lock up
 X if stdin is from a terminal.
@@ -57,6 +60,15 @@
 .BI \-fn " font"
 defines the font or font set used.
 .TP
+.BI \-x " xoffset"
+defines the offset from the left border of the screen.
+.TP
+.BI \-y " yoffset"
+defines the offset from the top border of the screen.
+.TP
+.BI \-w " width"
+defines the desired menu window width.
+.TP
 .BI \-nb " color"
 defines the normal background color.
 .IR #RGB ,
diff -u dmenu-4.4/dmenu.c dmenu/dmenu.c
--- dmenu-4.4/dmenu.c	2011-07-19 22:31:28.000000000 +0200
+++ dmenu/dmenu.c	2011-08-06 23:17:53.000000000 +0200
@@ -42,6 +42,9 @@
 static int bh, mw, mh;
 static int inputw, promptw;
 static int lines = 0;
+static int xoffset = 0;
+static int yoffset = 0;
+static int width = 0;
 static size_t cursor = 0;
 static const char *font = NULL;
 static const char *prompt = NULL;
@@ -53,6 +56,7 @@
 static unsigned long selcol[ColLast];
 static Atom utf8;
 static Bool topbar = True;
+static Bool quiet = False;
 static DC *dc;
 static Item *items = NULL;
 static Item *matches, *matchend;
@@ -75,6 +79,8 @@
 		}
 		else if(!strcmp(argv[i], "-b"))
 			topbar = False;
+		else if(!strcmp(argv[i], "-q"))
+			quiet = True;
 		else if(!strcmp(argv[i], "-f"))
 			fast = True;
 		else if(!strcmp(argv[i], "-i")) {
@@ -84,6 +90,12 @@
 		else if(i+1 == argc)
 			usage();
 		/* double flags */
+		else if(!strcmp(argv[i], "-x"))
+			xoffset = atoi(argv[++i]);
+		else if(!strcmp(argv[i], "-y"))
+			yoffset = atoi(argv[++i]);
+		else if(!strcmp(argv[i], "-w"))
+			width = atoi(argv[++i]);
 		else if(!strcmp(argv[i], "-l"))
 			lines = atoi(argv[++i]);
 		else if(!strcmp(argv[i], "-p"))
@@ -177,28 +189,30 @@
 	if((curpos = textnw(dc, text, cursor) + dc->h/2 - 2) < dc->w)
 		drawrect(dc, curpos, 2, 1, dc->h - 4, True, FG(dc, normcol));
 
-	if(lines > 0) {
-		dc->w = mw - dc->x;
-		for(item = curr; item != next; item = item->right) {
-			dc->y += dc->h;
-			drawtext(dc, item->text, (item == sel) ? selcol : normcol);
-		}
-	}
-	else if(matches) {
-		dc->x += inputw;
-		dc->w = textw(dc, "<");
-		if(curr->left)
-			drawtext(dc, "<", normcol);
-		for(item = curr; item != next; item = item->right) {
-			dc->x += dc->w;
-			dc->w = MIN(textw(dc, item->text), mw - dc->x - textw(dc, ">"));
-			drawtext(dc, item->text, (item == sel) ? selcol : normcol);
-		}
-		dc->w = textw(dc, ">");
-		dc->x = mw - dc->w;
-		if(next)
-			drawtext(dc, ">", normcol);
-	}
+    if(!quiet || strlen(text) > 0) {    
+        if(lines > 0) {
+            dc->w = mw - dc->x;
+            for(item = curr; item != next; item = item->right) {
+                dc->y += dc->h;
+                drawtext(dc, item->text, (item == sel) ? selcol : normcol);
+            }
+        }
+        else if(matches) {
+            dc->x += inputw;
+            dc->w = textw(dc, "<");
+            if(curr->left)
+                drawtext(dc, "<", normcol);
+            for(item = curr; item != next; item = item->right) {
+                dc->x += dc->w;
+                dc->w = MIN(textw(dc, item->text), mw - dc->x - textw(dc, ">"));
+                drawtext(dc, item->text, (item == sel) ? selcol : normcol);
+            }
+            dc->w = textw(dc, ">");
+            dc->x = mw - dc->w;
+            if(next)
+                drawtext(dc, ">", normcol);
+        }
+    }
 	mapdc(dc, win, mw, mh);
 }
 
@@ -501,7 +515,7 @@
 			if(INRECT(x, y, info[i].x_org, info[i].y_org, info[i].width, info[i].height))
 				break;
 		x = info[i].x_org;
-		y = info[i].y_org + (topbar ? 0 : info[i].height - mh);
+		y = info[i].y_org + (topbar ? yoffset : info[i].height - mh - yoffset);
 		mw = info[i].width;
 		XFree(info);
 	}
@@ -509,9 +523,13 @@
 #endif
 	{
 		x = 0;
-		y = topbar ? 0 : DisplayHeight(dc->dpy, screen) - mh;
+		y = topbar ? yoffset : DisplayHeight(dc->dpy, screen) - mh - yoffset;
 		mw = DisplayWidth(dc->dpy, screen);
 	}
+
+    x += xoffset;
+    mw = width ? width : mw;
+
 	promptw = prompt ? textw(dc, prompt) : 0;
 	inputw = MIN(inputw, mw/3);
 	match(False);
@@ -532,7 +550,8 @@
 
 void
 usage(void) {
-	fputs("usage: dmenu [-b] [-f] [-i] [-l lines] [-p prompt] [-fn font]\n"
+	fputs("usage: dmenu [-b] [-q] [-f] [-i] [-l lines] [-p prompt] [-fn font]\n"
+	      "             [-x xoffset] [-y yoffset] [-w width]\n"
 	      "             [-nb color] [-nf color] [-sb color] [-sf color] [-v]\n", stderr);
 	exit(EXIT_FAILURE);
 }

I made the following script to center dmenu's window:

#! /bin/sh

width_height=`xwininfo -root | grep -m 1 '\-geometry' | grep -oE '[0-9]+x[0-9]+'`

width=${width_height%x*}
height=${width_height#*x}
bar_width=$(( $width / 3 ))
left_shift=$(( ($width - $bar_width) / 2 ))
top_shift=$(( $height / 3 ))
fn='-*-terminus-medium-r-normal-*-20-*-*-*-*-*-iso10646-*'
nb='#171513'
nf='#575655'
sb='#171513'
sf='#929292'

dmenu_run -fn "$fn" -nb "$nb" -nf "$nf" -sb "$sb" -sf "$sf" -p '>' -l 3 -q -x $left_shift -y $top_shift -w $bar_width

Here's how it initially looks:
dmenulaunch.th.png

Last edited by bloom (2012-01-10 17:52:41)


gh · da · ds

Offline

#2 2011-08-20 14:17:32

falconindy
Developer
From: New York, USA
Registered: 2009-10-22
Posts: 4,111
Website

Re: An x, y, w patch for dmenu

This is pretty neat! You should post this on the suckless-dev ML.

edit: in case you're not afraid of bash, here's a bash3/awk alternative to calculating the offsets:

IFS=$'\n' read -r -d '' bar_width left_shift top_shift < \
    <(xwininfo -root | awk '/-geometry/ {
      split($2, dim, /[x+]/)

      bar_width = dim[1] / 3
      left_shift = (dim[1] - bar_width) / 2
      top_shift = dim[2] / 3
  
      printf "%.0f\n%.0f\n%.0f\n", bar_width, left_shift, top_shift
    }')

Last edited by falconindy (2011-08-20 14:31:24)

Offline

#3 2011-12-03 21:51:30

iv597
Member
From: United States
Registered: 2011-09-18
Posts: 96
Website

Re: An x, y, w patch for dmenu

I made an AUR package for this, if you don't mind. PKGBUILD is my first, so it might not be perfect, but it cleanly patches & builds against 4.4.1, so I went ahead and uploaded it.

https://aur.archlinux.org/packages.php?ID=54526


Currently running Arch on a Samsung Chromebook Pro (dual booted with ChromeOS), and various VPSes and Docker containers.

Dotfiles on Github

Offline

#4 2011-12-08 21:07:24

bloom
Member
Registered: 2010-08-18
Posts: 749
Website

Re: An x, y, w patch for dmenu

iv597 wrote:

I made an AUR package for this, if you don't mind. PKGBUILD is my first, so it might not be perfect, but it cleanly patches & builds against 4.4.1, so I went ahead and uploaded it.
https://aur.archlinux.org/packages.php?ID=54526

Please, go ahead.
If you want to name it based on the provided options it should be dmenu_xywq.


gh · da · ds

Offline

#5 2012-01-10 15:36:23

bloom
Member
Registered: 2010-08-18
Posts: 749
Website

Re: An x, y, w patch for dmenu

It is now dmenu_qxyw.


gh · da · ds

Offline

#6 2012-02-04 02:52:53

iv597
Member
From: United States
Registered: 2011-09-18
Posts: 96
Website

Re: An x, y, w patch for dmenu

I'll go ahead and update the PKGBUILD to grab it from your Github when I get a sec. I guess I'll go ahead and change the name, too, gotta post to AUR-General anyway for adoption of a couple packages, I'll just add the old package's removal request onto that big_smile


Currently running Arch on a Samsung Chromebook Pro (dual booted with ChromeOS), and various VPSes and Docker containers.

Dotfiles on Github

Offline

Board footer

Powered by FluxBB