Re: [dev] A general approach to master-slave layouts

2011-11-06 Thread lolilolicon
On Mon, Nov 7, 2011 at 3:28 AM, Connor Lane Smith c...@lubutu.com wrote:
 Hey,

 I've been thinking about this patch for a while, and I've knocked
 together a patch which takes an alternative approach, which seems to
 result in a simpler diff.

 In my patch each layout has three arrangement functions, one for the
 master, one the slave, and one a 'meta-layout' which defines how the
 master and slave booths are laid out. So dwm's tile() is achieved
 with an htile() meta-layout and vtile() master and slave.

 The patch is +12 lines over dwm tip.

 Thanks,
 cls


This is nice.
I've played around with it, and have had some progress:

  * Fixed the nmaster == 0 case.  The original patch would create an empty
master area.

  * Expoit the mfact  0 possibility.  When mfact is set to negative, use
the slave area as master area, and vice versa.  This makes it possible
to put masters on the right in tile, for example.  Adjusting setmfact()
for this, for now, but we should probably make this more flexible...

  * Port my original spiral layout to play with this patch.

I've attached the patch and the spiral layout as attachments.

And a question.  What is your plan on dealing with mfact/nmaster?  As I've
always insisted, they should be both monitor- and layout-specific.  What's
your opinion, and how would you approach this?

Thanks
diff -r ee36ffbd4252 config.def.h
--- a/config.def.h	Sun Nov 06 20:36:23 2011 +0100
+++ b/config.def.h	Mon Nov 07 11:03:20 2011 +0800
@@ -29,9 +29,9 @@
 
 static const Layout layouts[] = {
 	/* symbol arrange function */
-	{ []=,  tile },/* first entry is default */
-	{ ,  NULL },/* no layout function means floating behavior */
-	{ [M],  monocle },
+	{ []=,  tileh,   tilev,   tilev },   /* first entry is default */
+	{ ,  NULL,NULL,NULL },/* no layout function means floating behavior */
+	{ [M],  monocle, monocle, monocle },
 };
 
 /* key definitions */
diff -r ee36ffbd4252 dwm.c
--- a/dwm.c	Sun Nov 06 20:36:23 2011 +0100
+++ b/dwm.c	Mon Nov 07 11:03:20 2011 +0800
@@ -121,7 +121,9 @@
 
 typedef struct {
 	const char *symbol;
-	void (*arrange)(Monitor *);
+	void (*arrange)(Client *, float, XRectangle *, XRectangle *);
+	void (*master)(Client *, float, XRectangle *, XRectangle *);
+	void (*slave)(Client *, float, XRectangle *, XRectangle *);
 } Layout;
 
 struct Monitor {
@@ -199,7 +201,7 @@
 static void manage(Window w, XWindowAttributes *wa);
 static void mappingnotify(XEvent *e);
 static void maprequest(XEvent *e);
-static void monocle(Monitor *m);
+static void monocle(Client *c, float fact, XRectangle *r, XRectangle *rp);
 static void movemouse(const Arg *arg);
 static Client *nexttiled(Client *c);
 static void pop(Client *);
@@ -226,7 +228,8 @@
 static void tag(const Arg *arg);
 static void tagmon(const Arg *arg);
 static int textnw(const char *text, unsigned int len);
-static void tile(Monitor *);
+static void tileh(Client *c, float fact, XRectangle *r, XRectangle *rp);
+static void tilev(Client *c, float fact, XRectangle *r, XRectangle *rp);
 static void togglebar(const Arg *arg);
 static void togglefloating(const Arg *arg);
 static void toggletag(const Arg *arg);
@@ -403,9 +406,28 @@
 
 void
 arrangemon(Monitor *m) {
+	XRectangle r, rm, rt = { m-wx, m-wy, m-ww, m-wh };
+	Client *c;
+	float f;
+	int i, n;
+
 	strncpy(m-ltsymbol, m-lt[m-sellt]-symbol, sizeof m-ltsymbol);
-	if(m-lt[m-sellt]-arrange)
-		m-lt[m-sellt]-arrange(m);
+	if(m-lt[m-sellt]-arrange) {
+		for(n = 0, c = nexttiled(m-clients); c; c = nexttiled(c-next), n++);
+		if(n  0) {
+			if((f = (n  m-nmaster) ? (m-nmaster == 0 ? 0 : m-mfact) : 1)  0) {
+rm = rt;
+m-lt[m-sellt]-arrange(NULL, 1 + f, rm, rt);
+			}
+			else
+m-lt[m-sellt]-arrange(NULL, f, rt, rm);
+			for(i = 0, c = nexttiled(m-clients); c; c = nexttiled(c-next), i++)
+if(i  m-nmaster)
+	m-lt[m-sellt]-master(c, 1.0 / (MIN(n, m-nmaster) - i), rm, r);
+else
+	m-lt[m-sellt]-slave(c, 1.0 / (n - i), rt, r);
+		}
+	}
 	restack(m);
 }
 
@@ -1188,17 +1210,13 @@
 }
 
 void
-monocle(Monitor *m) {
-	unsigned int n = 0;
-	Client *c;
-
-	for(c = m-clients; c; c = c-next)
-		if(ISVISIBLE(c))
-			n++;
-	if(n  0) /* override layout symbol */
-		snprintf(m-ltsymbol, sizeof m-ltsymbol, [%d], n);
-	for(c = nexttiled(m-clients); c; c = nexttiled(c-next))
-		resize(c, m-wx, m-wy, m-ww - 2 * c-bw, m-wh - 2 * c-bw, False);
+monocle(Client *c, float fact, XRectangle *r, XRectangle *rp) {
+	rp-x  = r-x;
+	rp-y  = r-y;
+	rp-width  = r-width;
+	rp-height = r-height;
+	if(c)
+		resize(c, r-x, r-y, r-width - (2*c-bw), r-height - (2*c-bw), False);
 }
 
 void
@@ -1553,13 +1571,15 @@
 void
 setmfact(const Arg *arg) {
 	float f;
+	int i;
 
 	if(!arg || !selmon-lt[selmon-sellt]-arrange)
 		return;
-	f = arg-f  1.0 ? arg-f + selmon-mfact : arg-f - 1.0;
+	i = selmon-mfact  0 ? -1 : 1;
+	f = arg-f  1.0 ? arg-f + selmon-mfact * i : arg-f - 1.0;
 	if(f  0.1 || f  0.9)
 		return;
-	selmon-mfact = f;
+	

Re: [dev] A general approach to master-slave layouts

2011-11-06 Thread lolilolicon
On Mon, Nov 7, 2011 at 11:15 AM, lolilolicon loliloli...@gmail.com wrote:

  * Port my original spiral layout to play with this patch.

I've simplified the spiral layout by rusing tile{h,v}. Nice.
void
spiral(Client *c, float fact, XRectangle *r, XRectangle *rp) {
	if(fact == 0) {
		rp-width = rp-height = 0;
		return;
	}

	static int pos = 1;
	float f = fact == 1 ? 1 : 0.5;

	switch(pos) {
		case 0:  /* left */
			tileh(c, f, r, rp);
			pos = 1;
			break;
		case 1:  /* top */
			tilev(c, f, r, rp);
			pos = 2;
			break;
		case 2:  /* right */
			tileh(c, f, ((XRectangle){ r-x + r-width * (1 - f), r-y, r-width, r-height }), rp);
			r-width  -= rp-width;
			pos = 3;
			break;
		case 3:  /* bottom */
			tilev(c, f, ((XRectangle){ r-x, r-y + r-height * (1 - f), r-width, r-height }), rp);
			r-height -= rp-height;
			pos = 0;
			break;
	}

	if(fact == 1)
		pos = 1;  /* reset to initial value */
}


Re: [dev] Re: [dwm] A general approach to master-slave layouts

2011-11-02 Thread lolilolicon
I believe every master-slave layout, i.e., layouts where mfact/nmaster
make sense, should own its own mfact/nmaster value, not to be disturbed
by other layouts.  As said before, `col' and `tile' for example just
can't share the same mfact and still both look good.

Consequently, I decided to update the patch so mfact and nmaster are now
monitor- and layout-specific.  This should make the master-slave layouts
play nice with each other and thus make the idea more complete.

Also, the nice thing about this approach is that the config.h interface
is left unchanged.  mfact and nmaster values of each layout are
initialized to the global value mfact and nmaster; the user can also
implement layouts that force rules on mfact and nmaster if desired.

diff -r 904e923827cb -r 983f8ffd9f7c config.def.h
--- a/config.def.h  Mon Oct 31 20:09:27 2011 +0100
+++ b/config.def.h  Wed Nov 02 20:15:22 2011 +0800
@@ -32,6 +32,8 @@
{ []=,  tile },/* first entry is default */
{ ,  NULL },/* no layout function means floating behavior 
*/
{ [M],  monocle },
+   { TTT,  bstack },
+   { |||,  col },
 };

 /* key definitions */
@@ -66,6 +68,8 @@
{ MODKEY,   XK_t,  setlayout,  {.v =
layouts[0]} },
{ MODKEY,   XK_f,  setlayout,  {.v =
layouts[1]} },
{ MODKEY,   XK_m,  setlayout,  {.v =
layouts[2]} },
+   { MODKEY,   XK_s,  setlayout,  {.v =
layouts[3]} },
+   { MODKEY,   XK_c,  setlayout,  {.v =
layouts[4]} },
{ MODKEY,   XK_space,  setlayout,  {0} },
{ MODKEY|ShiftMask, XK_space,  togglefloating, {0} },
{ MODKEY,   XK_0,  view,   {.ui = ~0 } 
},
diff -r 904e923827cb -r 983f8ffd9f7c dwm.c
--- a/dwm.c Mon Oct 31 20:09:27 2011 +0100
+++ b/dwm.c Wed Nov 02 20:15:22 2011 +0800
@@ -122,26 +122,9 @@
void (*arrange)(Monitor *);
 } Layout;

-struct Monitor {
-   char ltsymbol[16];
-   float mfact;
-   int nmaster;
-   int num;
-   int by;   /* bar geometry */
-   int mx, my, mw, mh;   /* screen size */
-   int wx, wy, ww, wh;   /* window area  */
-   unsigned int seltags;
-   unsigned int sellt;
-   unsigned int tagset[2];
-   Bool showbar;
-   Bool topbar;
-   Client *clients;
-   Client *sel;
-   Client *stack;
-   Monitor *next;
-   Window barwin;
-   const Layout *lt[2];
-};
+typedef struct {
+   int x, y, w, h;
+} Rect;

 typedef struct {
const char *class;
@@ -153,18 +136,23 @@
 } Rule;

 /* function declarations */
+static void apply_mslts(Monitor *m, Bool hsplit,
+   void (*mltf)(Client **, Rect *, unsigned int),  /* master 
layout function */
+   void (*sltf)(Client **, Rect *, unsigned int)); /* slave layout 
function */
 static void applyrules(Client *c);
 static Bool applysizehints(Client *c, int *x, int *y, int *w, int *h,
Bool interact);
 static void arrange(Monitor *m);
 static void arrangemon(Monitor *m);
 static void attach(Client *c);
 static void attachstack(Client *c);
+static void bstack(Monitor *);
 static void buttonpress(XEvent *e);
 static void checkotherwm(void);
 static void cleanup(void);
 static void cleanupmon(Monitor *mon);
 static void clearurgent(Client *c);
 static void clientmessage(XEvent *e);
+static void col(Monitor *);
 static void configure(Client *c);
 static void configurenotify(XEvent *e);
 static void configurerequest(XEvent *e);
@@ -185,6 +173,7 @@
 static void focusmon(const Arg *arg);
 static void focusstack(const Arg *arg);
 static unsigned long getcolor(const char *colstr);
+static unsigned int getlayoutindex(const Layout *lt);
 static Bool getrootptr(int *x, int *y);
 static long getstate(Window w);
 static Bool gettextprop(Window w, Atom atom, char *text, unsigned int size);
@@ -194,6 +183,8 @@
 static void initfont(const char *fontstr);
 static void keypress(XEvent *e);
 static void killclient(const Arg *arg);
+static void lt_hstack(Client **c, Rect *r, unsigned int n);
+static void lt_vstack(Client **c, Rect *r, unsigned int n);
 static void manage(Window w, XWindowAttributes *wa);
 static void mappingnotify(XEvent *e);
 static void maprequest(XEvent *e);
@@ -281,11 +272,92 @@
 /* configuration, allows nested code to access above variables */
 #include config.h

+struct Monitor {
+   char ltsymbol[16];
+   float mfact[LENGTH(layouts)];
+   int nmaster[LENGTH(layouts)];
+   int num;
+   int by;   /* bar geometry */
+   int mx, my, mw, mh;   /* screen size */
+   int wx, wy, ww, wh;   /* window area  */
+   unsigned int seltags;
+   unsigned int sellt;
+   unsigned int tagset[2];
+   Bool showbar;
+   Bool topbar;
+   Client *clients;
+   Client *sel;
+   Client 

Re: [dev] Re: [dwm] A general approach to master-slave layouts

2011-11-01 Thread lolilolicon
On Tue, Nov 1, 2011 at 6:20 PM, Anselm R Garbe garb...@gmail.com wrote:
 On 1 November 2011 00:07, lolilolicon loliloli...@gmail.com wrote:
 Indeed mfact and nmaster being members of Layout does make more sense, and
 I made a patch which includes this change.

 Note that this may seem to add some SLOCs, but it actually reduces the
 amount of code required to implement the same layouts by avoiding code
 duplication.  See how tile, bstack and col are each defined using just a
 one-liner.  By defining two layout algorithms `lt_vstack` and `lt_hstack`,
 in combination with the hsplit switch, one can define 2 ** 2 * 2 = 8 such
 layouts, and if you count the (masters|slaves)-only layouts as separate
 ones, we got 10.  Add a third layout algorithm, and you have
 3 ** 2 * 2 + 3 = 21.  Sure, not all layouts are useful for everyone, but
 hopefully this will produce some interesting layouts suitable for your
 particular setup.

 Thanks for you patch, I looked at it and it is indeed interesting.
 However it needs further testing and review in order to be a candidate
 for mainline at some point.


Can't agree more.

 Some remarks:

 The change of the Layout struct makes it a lot harder to define
 layouts, as now one also has to understand the variables
 nmaster/mfact. Also nmaster/mfact are now layout specific variables
 that might not be used by other layouts. This lacks a bit conceptual
 clarity imho.


I also agree with what you said here, but let me clarify my intention.
I really think it more useful to make mfact/nmaster layout-specific,
otherwise I wounldn't have made the change to the Layout struct.  For
example, on my 1280x800 screen, mfact == 0.75 combined with nmaster == 2
in the n?col layout makes a nice layout, but the combination is very
bad for the tile layout.  As such, sharing mfact/nmaster across layouts
isn't exactly nice, nor is it dynamic enough.

But now I realize another problem with moving mfact/nmaster to Layout.
The issue is two monitors should be able to use different mfact/nmaster
values for the same layout; also, the setmfact/incnmaster functions
will not update the unselected monitor, but will have their effects all
of a sudden next time that monitor is arranged.
This makes me want to make nmaster/mfact specific to the monitor *and*
the layout.  And I also prefer achieving this in the least intrusive
way possible.

 What I'd really prefer is keeping the interface intact we had, a
 layout is just a function -- I have no objections that this function
 calls other functions or set up some variables to fit its needs. This
 would keep it equally simple to the user to define Layouts and leave
 the interface to be a function, rather than a function + variables.


You are absolutely right.  Now that I think of it, we can temporarily
set m-mfact and/or m-nmaster in a layout function before calling
apply_mslts, and restore the values afterwards.  For example, define
the col layout like this:

/* int term_width is the width of a terminal (e.g. 80 characters) */
void
col(Monitor *m) {
float mfact = m-mfact;
int nmaster = m-nmaster;
/* masters will be term_width wide */
m-nmaster = MIN(nmaster, m-ww / term_width);
m-mfact = (float)term_width * m-nmaster / m-ww;
apply_mslts(m, False, lt_hstack, lt_vstack);
m-mfact = mfact;
m-nmaster = nmaster;
}

A bit back-and-forth with the mfact calculation (since we will calculate
back to the width in apply_mslts), but it's a fair compromise, I guess.

 Also I'm not absolutely happy about the introduction of the Booth
 struct, I would rename that into Rect as we have used a similar name
 in other areas. Having said this, I'm in favor of *not* using
 XRectangle where possible, in order to keep the core code of dwm X
 agnostic (which is one 6.0 goal btw).


Bah, Booth is cute!  Just kidding; I knew it would sound strange and
probably have to be renamed.  Here we go, Rect it is.

 Cheers,
 Anselm





Re: [dev] Re: [dwm] A general approach to master-slave layouts

2011-11-01 Thread lolilolicon
On Tue, Nov 1, 2011 at 11:38 PM, Anselm R Garbe garb...@gmail.com wrote:
 On 1 November 2011 16:27, lolilolicon loliloli...@gmail.com wrote:
 But now I realize another problem with moving mfact/nmaster to Layout.
 The issue is two monitors should be able to use different mfact/nmaster
 values for the same layout; also, the setmfact/incnmaster functions
 will not update the unselected monitor, but will have their effects all
 of a sudden next time that monitor is arranged.
 This makes me want to make nmaster/mfact specific to the monitor *and*
 the layout.  And I also prefer achieving this in the least intrusive
 way possible.

 Exactly this is the main problem. You could work around it with
 changing monitor as follows:

  struct Monitor {
        char ltsymbol[16];
 -       float mfact;
 -       int nmaster;
 +       float mfact[LENGTH(layouts)];
 +       int nmaster[LENGTH(layouts)];
        int num;
        int by;               /* bar geometry */
        int mx, my, mw, mh;   /* screen size */

 however this would require some reshuffling of the config.h inclusion
 and also changes in various places. So I doubt it would be necessary
 at all. Just stick with nmaster/mfact in Monitor.


Hmm, I think the difficulty is to track the index of the current layout
in the layouts array.  I'm not sure how.  I'd like to stick with the
current Monitor struct.

 You are absolutely right.  Now that I think of it, we can temporarily
 set m-mfact and/or m-nmaster in a layout function before calling
 apply_mslts, and restore the values afterwards.  For example, define
 the col layout like this:

    /* int term_width is the width of a terminal (e.g. 80 characters) */
    void
    col(Monitor *m) {
        float mfact = m-mfact;
        int nmaster = m-nmaster;
        /* masters will be term_width wide */
        m-nmaster = MIN(nmaster, m-ww / term_width);
        m-mfact = (float)term_width * m-nmaster / m-ww;
        apply_mslts(m, False, lt_hstack, lt_vstack);
        m-mfact = mfact;
        m-nmaster = nmaster;
    }

 A bit back-and-forth with the mfact calculation (since we will calculate
 back to the width in apply_mslts), but it's a fair compromise, I guess.

 This could work for a patch, but I don't think this is a great way of
 programming for mainline, since manipulating and restoring
 nmaster/mfact for the time being is quite ugly. ;)

Well, it's a compromise.  Would you feel it's less ugly if I define the
apply_mslts function like this:

tatic void apply_mslts(Monitor *m, Bool hsplit,
float mfact, int nmaster,
void (*mltf)(Client **, Booth *, unsigned int),
void (*sltf)(Client **, Booth *, unsigned int)) {
/* uses mfact instead of m-mfact, nmaster intead of m-nmaster */
}

and define the layouts like:

void
col(Monitor *m) {
      int nmaster = MIN(m-nmaster, m-ww / term_width);
      float mfact = (float)term_width * nmaster / m-ww;
  apply_mslts(m, False, mfact, nmaster, lt_hstack, lt_vstack);
}
void
tile(Monitor *m) {
  apply_mslts(m, False, m-mfact, m-nmaster, lt_vstack, lt_vstack);
}

Basically the same thing, I guess it's still ugly, but does it feel less
ugly? :D


 Cheers,
 Anselm





[dev] A general approach to master-slave layouts

2011-10-31 Thread lolilolicon
The idea of having more than one master windows is brilliant.  The `tile'
layout in current hg tip basically splits the master and slave areas
vertically, and tiles windows in each of the two areas using a vertical
stacking algorithm.  The `ncol' layout does it slightly differently by
tilling the master windows using a horizontal stacking algorithm.  The
`n?bstack' layout also does it slightly differently, by splitting the
master and slave areas horizontally, and tiles windows in each of them
using a horizontal stacking algorithm.

All of these layouts fit in a generalized model.  Basically, there're two
things that differentiate one master-slave layout from another:

  1. How the master and slave areas are separated.  Practically, the most
  useful way to do this is simply split the screen in two parts, either
  vertically, or horizontally.

  2. What layout is used in each of the master and slave areas.  We can
  use different layouts for the masters and the slaves.  We should reuse
  the layout algorithms when we can.

With this model in mind, I came up with the function apply_mslts(), i.e.
apply master-slave layouts, which takes care of the two things stated
above.  The actual layout algorithms are defined in the lt_* functions:

  lt_hstack tiles windows in a horizontal stack, i.e. columns.
  lt_vstack tiles windows in a vertical stack, i.e. rows.
  lt_grid tiles windows in a (gapless) grid.
  lt_monocle stacks windows, each maximized to fill the booth.

The booth is the box in which the layout is performed.  Such functions
are simpler and easier to read.  And they are reusable.

To define a master-slave layout is as simple as:

  static void
  grid(Monitor *m) {
apply_mslts(m, False, lt_vstack, lt_grid);
  }

Here `False` means split master and slave areas vertically; lt_vstack is
applied to the master area, and lt_grid to the slaves.  I've never seen
such a layout before, you may find it interesting too.

To test this out, simply grab the hg tip, #include mslts.c in config.h,
add some example layouts such as `grid', bind a key combo, `make`, and
run.  Adjust the nmaster value with Mod + d/i, and mfact with Mod + h/j
to see the effects.

Also, this approach accepts nmaster being 0, in which case, all windows
are slaves, and are thus tiled using the slaves' layout algorithm.  This
should be the case for the current hg tip, too, IMO.

Finally, I'm not really good at C yet, so the code could probably use a
whole lot of improvement.  I'd really appreciate it if you could review
the code and help me improve it, because I really like this idea.

The code is in the attachment.
typedef struct {
	int x, y, w, h;
} Booth;

static void apply_lt(Monitor *m, void (*ltf)(Client **, Booth *, unsigned int));
static void apply_mslts(Monitor *m, Bool hsplit,
		void (*mltf)(Client **, Booth *, unsigned int),  /* master layout func */
		void (*sltf)(Client **, Booth *, unsigned int)); /* slave layout func */
static void lt_hstack(Client **c, Booth *b, unsigned int n);
static void lt_vstack(Client **c, Booth *b, unsigned int n);
static void lt_grid(Client **c, Booth *b, unsigned int n);
static void lt_monocle(Client **c, Booth *b, unsigned int n);

/* Example master-slave layouts */

static void ntile(Monitor *m);
static void ncol(Monitor *m);
static void bstack(Monitor *m);
static void grid(Monitor *m);

static void
ntile(Monitor *m) {
	apply_mslts(m, False, lt_vstack, lt_vstack);
}

static void
ncol(Monitor *m) {
	apply_mslts(m, False, lt_hstack, lt_vstack);
}

static void
bstack(Monitor *m) {
	apply_mslts(m, True, lt_hstack, lt_hstack);
}

static void
grid(Monitor *m) {
	apply_mslts(m, False, lt_vstack, lt_grid);
}

/* Functions that apply layouts */

static void
apply_lt(Monitor *m, void (*ltf)(Client **, Booth *, unsigned int)) {
  unsigned int n;
  Client *c;

	for(n = 0, c = nexttiled(m-clients); c; c = nexttiled(c-next), n++);
	if(n == 0)
		return;

	Booth b = { .x = m-wx, .y = m-wy, .w = m-ww, .h = m-wh };
	(*ltf)(c, b, n);
}

static void
apply_mslts(Monitor *m, Bool hsplit,
		void (*mltf)(Client **, Booth *, unsigned int),
		void (*sltf)(Client **, Booth *, unsigned int)) {
	unsigned int nm, n;
	Client *c;

	for(n = 0, c = nexttiled(m-clients); c; c = nexttiled(c-next), n++);
	if(n == 0)
		return;

	nm = MIN(n, m-nmaster);  /* number of masters */

	if (nm == 0) {
		/* all slaves */
		c = m-clients;
		Booth b = { .x = m-wx, .y = m-wy, .w = m-ww, .h = m-wh };
		(*sltf)(c, b, n);
	}
	else if(n  nm) {
		/* masters and slaves */
		c = m-clients;
		if(hsplit) {
			/* masters above slaves */
			Booth b = { .x = m-wx, .y = m-wy, .w = m-ww, .h = m-wh * m-mfact };
			(*mltf)(c, b, nm);
			b.y += b.h;
			b.h = m-wh - b.h;
			(*sltf)(c, b, n - nm);
		}
		else {
			/* masters at the left of slaves */
			Booth b = { .x = m-wx, .y = m-wy, .w = m-ww * m-mfact, .h = m-wh };
			(*mltf)(c, b, nm);
			b.x += b.w;
			b.w = m-ww - b.w;
			(*sltf)(c, b, n - nm);
		}
	}
	else {
		/* all masters */
		c = m-clients;
		Booth b = { 

[dev] [dwm] A general approach to master-slave layouts

2011-10-31 Thread lolilolicon
The idea of having more than one master window is brilliant.  The `tile'
layout in current hg tip basically splits the master and slave areas
vertically, and tiles windows in each of the two areas using a vertical
stacking algorithm.  The `ncol' layout does it slightly differently by
tilling the master windows using a horizontal stacking algorithm.  The
`n?bstack' layout also does it slightly differently, by splitting the
master and slave areas horizontally, and tiles windows in each of them
using a horizontal stacking algorithm.

All of these layouts fit in a generalized model.  Basically, there're two
things that differentiate one master-slave layout from another:

  1. How the master and slave areas are separated.  Practically, the most
  useful way to do this is simply split the screen in two parts, either
  vertically, or horizontally.

  2. What layout is used in each of the master and slave areas.  We can
  use different layouts for the masters and the slaves.  We should reuse
  the layout algorithms when we can.

With this model in mind, I came up with the function apply_mslts(), i.e.
apply master-slave layouts, which takes care of the two things stated
above.  The actual layout algorithms are defined in the lt_* functions:

  lt_hstack tiles windows in a horizontal stack, i.e. columns.
  lt_vstack tiles windows in a vertical stack, i.e. rows.
  lt_grid tiles windows in a (gapless) grid.
  lt_monocle stacks windows, each maximized to fill the booth.

The booth is the box in which the layout is performed.  Such functions
are simpler and easier to read.  And they are reusable.

To define a master-slave layout is as simple as:

  static void
  grid(Monitor *m) {
apply_mslts(m, False, lt_vstack, lt_grid);
  }

Here `False` means split master and slave areas vertically; lt_vstack is
applied to the master area, and lt_grid to the slaves.  I've never seen
such a layout before, you may find it interesting too.

To test this out, simply grab the hg tip, #include mslts.c in config.h,
add some example layouts such as `grid', bind a key combo, `make`, and
run.  Adjust the nmaster value with Mod + d/i, and mfact with Mod + h/l
to see the effects.

Also, this approach accepts nmaster being 0, in which case, all windows
are slaves, and are thus tiled using the slaves' layout algorithm.  This
should be the case for the current hg tip, too, IMO.

Finally, I'm not really good at C yet, so the code could probably use a
whole lot of improvement.  I'd really appreciate it if you could review
the code and help me improve it, because I really like this idea.

The code is in the attachment.

/*
Resend this due to missing [dwm] tag in the subject, and an error in the
code.  Sorry for the inconvenience.
*/



Re: [dev] Re: [dwm] A general approach to master-slave layouts

2011-10-31 Thread lolilolicon
On Mon, Oct 31, 2011 at 10:19 PM, Thomas Dahms thmsd...@googlemail.com wrote:

 That looks interesting. I have one suggestion for a simplification:
 I guess you can get rid of the functions combining the master and
 slave layouts by modifying setlayout() to take three arguments (the
 two layouts and the direction of master/slave splitting). This way you
 could combine any two layouts in the key binding section of config.h.

I don't think we can do this with the current Arg.  I also don't see the
benefit of this over defining the layouts.  If the user wants to combine
two layout algorithms, he can always define a layout in as few as three
lines in config.h.  Please elaborate if I misunderstand.

Also, the code is so far in no way in conflict with the dwm code.  This
general approach is also more flexible.  For example, the example `ntile'
layout can replace `tile' in dwm.c, and `monocle' in dwm.c can be defined
via `apply_lt` using `lt_monocle`.

Actually, `apply_lt` can be removed, since `apply_mslts` does the same
thing when nmaster == 0.  I'm thinking of making nmaster a member of
the Layout structure, instead of the current Monitor.  This way, we can
make all windows slaves in the `grid' layout, while having two masters
when we switch to `tile'.  The same applies to mfact- the `ncol' layout
certainly needs a bigger mfact than `tile', for example.  Finally, neither
nmaster nor mfact makes sense in non-master-slave layouts (if you still
use those, that is ;).  Oh, and it would be nice if mfact increased when
nmaster increased in the `ncol' layout, too.  Maybe another function
as a member of Layout, which would be executed to set mfact as a hook
whenever nmaster changes?

Since the current tile, monocle, and proposed bstack layouts are each a
special case of the mslts approach, and mslts is more powerful (and I do
think is simpler and easier to read), and if you care, mslts will likely
decrease the SLOC due to removal of duplicated code, I think mslts could
be accepted into mainline.  What do you think?


 --
 Thomas Dahms





Re: [dev] Re: [dwm] A general approach to master-slave layouts

2011-10-31 Thread lolilolicon
On Tue, Nov 1, 2011 at 12:11 AM, lolilolicon loliloli...@gmail.com wrote:

 Actually, `apply_lt` can be removed, since `apply_mslts` does the same
 thing when nmaster == 0.  I'm thinking of making nmaster a member of
 the Layout structure, instead of the current Monitor.  This way, we can
 make all windows slaves in the `grid' layout, while having two masters
 when we switch to `tile'.  The same applies to mfact- the `ncol' layout
 certainly needs a bigger mfact than `tile', for example.  Finally, neither
 nmaster nor mfact makes sense in non-master-slave layouts (if you still
 use those, that is ;).  Oh, and it would be nice if mfact increased when
 nmaster increased in the `ncol' layout, too.  Maybe another function
 as a member of Layout, which would be executed to set mfact as a hook
 whenever nmaster changes?


Indeed mfact and nmaster being members of Layout does make more sense, and
I made a patch which includes this change.

Since I don't know much about hg, I just did a `hg export`, and attach the
produced patch as attachment instead of inline.  The commit message should
describe what has been done, and the code should explain itself.

Note that this may seem to add some SLOCs, but it actually reduces the
amount of code required to implement the same layouts by avoiding code
duplication.  See how tile, bstack and col are each defined using just a
one-liner.  By defining two layout algorithms `lt_vstack` and `lt_hstack`,
in combination with the hsplit switch, one can define 2 ** 2 * 2 = 8 such
layouts, and if you count the (masters|slaves)-only layouts as separate
ones, we got 10.  Add a third layout algorithm, and you have
3 ** 2 * 2 + 3 = 21.  Sure, not all layouts are useful for everyone, but
hopefully this will produce some interesting layouts suitable for your
particular setup.
# HG changeset patch
# User lolilolicon loliloli...@gmail.com
# Date 1320098001 -28800
# Node ID f35ce5cc96363a813f91e64f6eda30504052eeed
# Parent  904e923827cb010abb7a31298264548946616d92
A general approach to master-slave layouts

This makes the actual code implementing layout algorithms reusable.
Apply two separate layout algorithms to the master area and the slave
area.  The master and slave areas are separated by either vertical or
horizontal split.

The `tile' algorithm is split out as `lt_vstack` and the `tile' function
is now just a one-liner.  Due to the reusability, the `bstack' and `col'
layouts are added with few lines of code.  Other interesting layout
combinations can be easily added in the same manner.

Move mfact and nmaster to the Layout structure, so that each layout can
have its own mfact and nmaster.  This makes sense when using several
master-slave layouts, e.g., the `col' layout will usually use a mfact
larger than `tile'.

diff --git a/config.def.h b/config.def.h
--- a/config.def.h
+++ b/config.def.h
@@ -23,15 +23,15 @@
 };
 
 /* layout(s) */
-static const float mfact  = 0.55; /* factor of master area size [0.05..0.95] */
-static const int nmaster  = 1;/* number of clients in master area */
 static const Bool resizehints = True; /* True means respect size hints in tiled resizals */
 
-static const Layout layouts[] = {
-	/* symbol arrange function */
-	{ []=,  tile },/* first entry is default */
-	{ ,  NULL },/* no layout function means floating behavior */
-	{ [M],  monocle },
+static Layout layouts[] = {
+	/* symbol arrange function mfactnmaster */
+	{ []=,  tile,0.55,1 },  /* first entry is default */
+	{ ,  NULL,0.5, 0 },  /* no layout function means floating behavior */
+	{ [M],  monocle, 0.5, 0 },
+	{ TTT,  bstack,  0.55,1 },
+	{ |||,  col, 0.75,2 },
 };
 
 /* key definitions */
@@ -66,6 +66,8 @@
 	{ MODKEY,   XK_t,  setlayout,  {.v = layouts[0]} },
 	{ MODKEY,   XK_f,  setlayout,  {.v = layouts[1]} },
 	{ MODKEY,   XK_m,  setlayout,  {.v = layouts[2]} },
+	{ MODKEY,   XK_s,  setlayout,  {.v = layouts[3]} },
+	{ MODKEY,   XK_c,  setlayout,  {.v = layouts[4]} },
 	{ MODKEY,   XK_space,  setlayout,  {0} },
 	{ MODKEY|ShiftMask, XK_space,  togglefloating, {0} },
 	{ MODKEY,   XK_0,  view,   {.ui = ~0 } },
diff --git a/dwm.c b/dwm.c
--- a/dwm.c
+++ b/dwm.c
@@ -71,6 +71,10 @@
 } Arg;
 
 typedef struct {
+	int x, y, w, h;
+} Booth;
+
+typedef struct {
 	unsigned int click;
 	unsigned int mask;
 	unsigned int button;
@@ -120,12 +124,12 @@
 typedef struct {
 	const char *symbol;
 	void (*arrange)(Monitor *);
+	float mfact;
+	int nmaster;
 } Layout;
 
 struct Monitor {
 	char ltsymbol[16];
-	float mfact;
-	int nmaster;
 	int num;
 	int by;   /* bar geometry */
 	int mx, my, mw, mh;   /* screen size */
@@ -140,7 +144,7

Re: [dev] Re: [dwm] A general approach to master-slave layouts

2011-10-31 Thread lolilolicon
On Tue, Nov 1, 2011 at 7:36 AM, Rob robpill...@gmail.com wrote:

 I don't have much time today, or possibly tomorrow, but I'm interested
 in this patch, it sounds almost like it recurses on each sub-section of
 the total area, applying a different layout function each time, except
 it's limited to two calls, one for the master area and one for the
 slave.

It's only one patch, which I sent in my last mail, so not much really :)

The core is the `apply_mslts' funtion.  It walks all clients like any
tiling layout would do, e.g., the `tile' function defined in the patch
simply calls `apply_mslts(m, False, lt_vstack, lt_vstack)`, and it should
do the layout exactly the same way the original `tile' would do, no extra
wasted work.  The code should be clear, but maybe note that the mltf/sltf
functions modify `c'.

 Either way, I'm hoping to try out your patch(es) at some point
 this week, and hoping to mess around with the key bindings, I assume you
 can change the master layout while keeping the slave one the same with a
 binding, right?

Not really.  DWM knows only about a single layout per monitor, even if we
set the masters to temporarily use a different layout algorithm, but not
update the currently selected layout name, DWM will rearrange the masters
back to the selected layout whenever arrangemon() is called, which happens
probably before you realize it ;).  That said, you can always define two
layouts which differ only in the master layout, (e.g. `tile' and `col').
Or if we feel progressive, let's make DWM aware of the master layout as
well as the slave layout, although I don't see practical need so far.

Similarly, I also considered to enable toggling master/slave splitting
direction, effectively rotating the layout, or even allow flipping,
but then thought it not useful in practice...


 Cheers,
 Rob




Re: [dev] A general approach to master-slave layouts

2011-10-31 Thread lolilolicon
On Tue, Nov 1, 2011 at 8:41 AM, Connor Lane Smith c...@lubutu.com wrote:
 Hey,

 On 31/10/2011, lolilolicon loliloli...@gmail.com wrote:
 The idea of having more than one master windows is brilliant.  The `tile'
 layout in current hg tip basically splits the master and slave areas
 vertically, and tiles windows in each of the two areas using a vertical
 stacking algorithm.

 I'll be interested to see where this goes. The code is still a bit raw
 at the moment, but I like the idea. I wonder how simple we can get
 this patch...

Indeed, I post it here for all your suckless energy to do my money laundry ;)


 cls





Re: [dev] Ranger, a textbased filemanager

2011-10-24 Thread lolilolicon
On Mon, Oct 24, 2011 at 6:01 AM, Bjartur Thorlacius
svartma...@gmail.com wrote:
 if the task is 'waste a bunch of screen real estate' then no, ranger
 is a far better choice

 The current combination of a shell and a terminal emulator is
 horrible. I've found myself doing stuff like:

 exec /dev/tty1 /dev/tty2 2/dev/tty1
 #optionally stty -echo
 while read
 do    clear
      $REPLY
 done

 Why in Mímir's name do error messages and output get written to where
 my input is echoed?



This could to be an interesting idea. I'm thinking 3 column terminal
(stdin, stdout, stderr), as well as remote control...



Re: [dev] [dmenu] dmenu_run improvements

2011-07-24 Thread lolilolicon
On 07/24/11 at 01:34am, Dave Reisner wrote:
 #!/bin/sh
 
 CACHE=${XDG_CACHE_HOME:-$HOME/.cache}/dmenu_run
 IFS=:
 LC_COLLLATE=C
You got a typo here: LC_COLLATE

 
 gencache() {
   lsx $PATH | sort -u $CACHE
 }
Since LC_COLLATE is only used for sort, we might as well just use:

  LC_COLLATE=C sort

 
 if [ ! -e $CACHE ]; then
   mkdir -p ${CACHE%/*}
   gencache
 fi
 
 for path in $PATH; do
   if [ $path -nt $CACHE ]; then
 gencache
 break
   fi
 done
Much better than `ls -t', congratulations.
If $CACHE does not exist, there's no need to compare timestamps, so
let's puts an `else' there.

 unset IFS
 
 cmd=$(dmenu $@  $CACHE)  eval exec $cmd
Yeah, I see you just hate backticks :P



Re: [dev] [dmenu] dmenu_run improvements

2011-07-24 Thread lolilolicon
On 07/24/11 at 11:38am, anonymous wrote:
 On Sun, Jul 24, 2011 at 02:34:22PM +0800, lolilolicon wrote:
   unset IFS
   
   cmd=$(dmenu $@  $CACHE)  eval exec $cmd
  Yeah, I see you just hate backticks :P
  
 
 There is a difference:
 
 % echo `echo '\\'`
 \
 % echo $(echo '\\')
 \\

You're right. The backquoted form is broken even with no nesting.
Now I'm officially a member of the anti-backticks club. Thank you.



Re: [dev] [dmenu] dmenu_run improvements

2011-07-24 Thread lolilolicon
On Sun, Jul 24, 2011 at 4:40 PM, Anselm R Garbe garb...@gmail.com wrote:
 On 24 July 2011 08:38, anonymous p37si...@lavabit.com wrote:
 On Sun, Jul 24, 2011 at 02:34:22PM +0800, lolilolicon wrote:
  unset IFS
 
  cmd=$(dmenu $@  $CACHE)  eval exec $cmd
 Yeah, I see you just hate backticks :P


 There is a difference:

    % echo `echo '\\'`
    \
    % echo $(echo '\\')
    \\

 Yes, but bash'isms are a NO GO in suckless.org shell scripts :)

 Cheers,
 Anselm



This is no bashism.
AFAIK, $(command) is in the POSIX shell specification:
http://pubs.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06_03



Re: [dev] [dmenu] dmenu_run improvements

2011-07-24 Thread lolilolicon
On Sun, Jul 24, 2011 at 4:39 PM, Anselm R Garbe garb...@gmail.com wrote:
 On 24 July 2011 06:34, Dave Reisner d...@falconindy.com wrote:
 On Sun, Jul 24, 2011 at 12:35:19PM +0800, lolilolicon wrote:
 dmenu_run doesn't really run the user input as a shell command line.
 For instance, run dmenu_run from a terminal, then in the menu type:

   echo hello\ world

 The terminal output is hello\ world instead of hello world.

 `eval' solves the problem, but when it comes to eval, I can't really
 be sure, so please point out the possible errors/risks.

 Assuredly the least of the evils in this script -- the eval is
 necessary. More noteworthy is the parsing of ls here, which can easily
 be refactored out and still be /bin/sh compat. It also explodes on first
 run, and then there's the needless invocation of mkdir every time the
 cache is regenerated. suckless could suck a lot less at shell scripting.
 dmenu_run has gone through several iterations of bad and worse.

 d


 #!/bin/sh

 CACHE=${XDG_CACHE_HOME:-$HOME/.cache}/dmenu_run
 IFS=:
 LC_COLLLATE=C

 gencache() {
  lsx $PATH | sort -u $CACHE
 }

 if [ ! -e $CACHE ]; then
  mkdir -p ${CACHE%/*}
  gencache
 fi

 for path in $PATH; do
  if [ $path -nt $CACHE ]; then
    gencache
    break
  fi
 done

 Am I right that the previous loop runs gencache n times, under the
 assumption that each path component contains newer files?

 Kind regards,
 Anselm



No, note the `break'.



Re: [dev] [dmenu] dmenu_run improvements

2011-07-24 Thread lolilolicon
On Sun, Jul 24, 2011 at 5:06 PM, Anselm R Garbe garb...@gmail.com wrote:
 Nevertheless, I can see that script should be improved (not using the
 ls -dt invocation), but I prefer the back ticks (even if $(..) is
 POSIX, there were a couple of issues in the past that I barely
 remember) and I want explicit test calls, I don't like the [ ... ]
 syntax sugar.

 Thanks,
 Anselm



Fine, as long as it doesn't break anything, I can live with these two
backticks.
Since I'm the thread starter, may I conclude this with the following?

#!/bin/sh
CACHE=${XDG_CACHE_HOME:-$HOME/.cache}/dmenu_run
(
IFS=:
gen_cache() {
lsx $PATH | LC_COLLATE=C sort -u  $CACHE
}
if test -e $CACHE; then
for path in $PATH; do
if test $path -nt $CACHE; then
gen_cache
break
fi
done
else
mkdir -p ${CACHE%/*}
gen_cache
fi
)
cmd=`dmenu $@  $CACHE`  eval exec $cmd

NOTE:
The (subshell) is used so the declarations won't get inherented, but
the user still has access to the $CACHE and $cmd environments.



Re: [dev] [dmenu] dmenu_run improvements

2011-07-24 Thread lolilolicon
On Sun, Jul 24, 2011 at 6:41 PM, lolilolicon loliloli...@gmail.com wrote:
 cmd=`dmenu $@  $CACHE`  eval exec $cmd

 NOTE:
 The (subshell) is used so the declarations won't get inherented, but
 the user still has access to the $CACHE and $cmd environments.


Hmm, maybe instead of `eval exec', we could just use `exec sh -c' instead?

  cmd=`dmenu $@  $CACHE` || exit $?
  exec sh -c $cmd

The benefits are:

1. Only exported environment variables will be available to the user command.
2. The user can run any shell command, including, e.g.,

  if true; then echo hello\ world; fi

Correct me if I'm missing something here. Thanks.



Re: [dev] [dmenu] dmenu_run improvements

2011-07-24 Thread lolilolicon
On Sun, Jul 24, 2011 at 9:09 PM, Connor Lane Smith c...@lubutu.com wrote:
 On 24 July 2011 06:34, Dave Reisner d...@falconindy.com wrote:
 if [ $path -nt $CACHE ]; then

 'test -nt' is non-portable. I think you've just discovered why we use
 the 'ls -dt' hack.

 I agree that dmenu_run isn't the nicest script in existence. But
 because of the tedious limitations of POSIX we don't have much choice.

Sorry, but can you give an example where `test -nt' is not available?
Or can you point out what do you refer to to determine the portability
of a shell script?

According to Greg's wiki [1], `test -nt' is not supported by dash,
although it works here with dash 0.5.6.1. Even if you must support the
older versions that does not know about `test -nt', you can use find:

  test `find $path -prune -newer $CACHE`

as a drop-in replacement, which is better than `ls -dt' after all.

[1] http://mywiki.wooledge.org/Bashism



Re: [dev] Re: [dmenu] dmenu_run improvements

2011-07-24 Thread lolilolicon
On Sun, Jul 24, 2011 at 10:08 PM, Christian Neukirchen
chneukirc...@gmail.com wrote:
 anonymous p37si...@lavabit.com writes:

 On Sun, Jul 24, 2011 at 02:34:22PM +0800, lolilolicon wrote:
  unset IFS
 
  cmd=$(dmenu $@  $CACHE)  eval exec $cmd
 Yeah, I see you just hate backticks :P


 There is a difference:

     % echo `echo '\\'`
     \
     % echo $(echo '\\')
     \\

 That must be a bashism, can't reproduce in dash, mksh, zsh.

 --
 Christian Neukirchen  chneukirc...@gmail.com  http://chneukirchen.org




The builtin echo may differ from /bin/echo. For example, here in dash:

$ echo '\\'
\
$ echo `echo '\\'`
\
$ echo $(echo '\\')
\

$ /bin/echo '\\'
\\
$ /bin/echo `/bin/echo '\\'`
\
$ /bin/echo $(/bin/echo '\\')
\\

In fact the builtin echo really sucks:

$ echo \\
\
$ echo 
\



Re: [dev] [dmenu] dmenu_run improvements

2011-07-24 Thread lolilolicon
On Sun, Jul 24, 2011 at 10:09 PM, Dave Reisner d...@falconindy.com wrote:
 On Sun, Jul 24, 2011 at 10:00:09PM +0800, lolilolicon wrote:
 Sorry, but can you give an example where `test -nt' is not available?
 Or can you point out what do you refer to to determine the portability
 of a shell script?

 I usually reference opengroup for POSIX util specs. I do love the
 wooledge wiki, though.

 http://pubs.opengroup.org/onlinepubs/95399/utilities/test.html

 d

Thanks Dave for the tip.
No wonder, I was looking at the Shell Command Language page.

Cheers.



Re: [dev] Re: [dmenu] dmenu_run improvements

2011-07-24 Thread lolilolicon
On Sun, Jul 24, 2011 at 10:30 PM, lolilolicon loliloli...@gmail.com wrote:
 On Sun, Jul 24, 2011 at 10:08 PM, Christian Neukirchen
 chneukirc...@gmail.com wrote:
 anonymous p37si...@lavabit.com writes:

 On Sun, Jul 24, 2011 at 02:34:22PM +0800, lolilolicon wrote:
  unset IFS
 
  cmd=$(dmenu $@  $CACHE)  eval exec $cmd
 Yeah, I see you just hate backticks :P


 There is a difference:

     % echo `echo '\\'`
     \
     % echo $(echo '\\')
     \\

 That must be a bashism, can't reproduce in dash, mksh, zsh.

 --
 Christian Neukirchen  chneukirc...@gmail.com  http://chneukirchen.org




 The builtin echo may differ from /bin/echo. For example, here in dash:

 $ echo '\\'
 \
 $ echo `echo '\\'`
 \
 $ echo $(echo '\\')
 \

 $ /bin/echo '\\'
 \\
 $ /bin/echo `/bin/echo '\\'`
 \
 $ /bin/echo $(/bin/echo '\\')
 \\

 In fact the builtin echo really sucks:

 $ echo \\
 \
 $ echo 
 \


Sorry, but please allow me to rephrase the issue.
The `echo' builtin in dash by default behaves like `echo -e' in bash.
So it's a bit tricky to reproduce the difference in dash:

$ echo `echo ''`
\
$ echo $(echo '')
\\

Or, just use `printf %s':

$ printf '%s\n' `printf '%s\n' '\\'`
\
$ printf '%s\n' $(printf '%s\n' '\\')
\\

For the record, the sucky `echo' is what POSIX defines:
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/echo.html

And thank you Szabolcs Nagy for pointing me to the lastes spec.

Cheers.



[dev] [dmenu] dmenu_run improvements

2011-07-23 Thread lolilolicon
dmenu_run doesn't really run the user input as a shell command line.
For instance, run dmenu_run from a terminal, then in the menu type:

  echo hello\ world

The terminal output is hello\ world instead of hello world.

`eval' solves the problem, but when it comes to eval, I can't really
be sure, so please point out the possible errors/risks.

`LC_ALL=C' is for sort.

diff -up a/dmenu_run b/dmenu_run
--- a/dmenu_run 1970-01-01 00:00:00.0 +
+++ b/dmenu_run 1970-01-01 00:00:00.0 +
@@ -1,9 +1,9 @@
 #!/bin/sh
 CACHE=${XDG_CACHE_HOME:-$HOME/.cache}/dmenu_run
 (
-   IFS=:
+   IFS=: LC_ALL=C
if test `ls -dt $PATH $CACHE 2 /dev/null | sed 1q` != $CACHE; 
then
mkdir -p `dirname $CACHE`  lsx $PATH | sort -u  $CACHE
fi
 )
-cmd=`dmenu $@  $CACHE`  exec $cmd
+cmd=`dmenu $@  $CACHE`  eval exec $cmd



[dev][dmenu] loadfont() segmentation fault patch

2011-07-22 Thread lolilolicon
To reproduce the segmentation fault:

dmenu -fn 
-windows-montecarlo-medium-r-normal--11-110-72-72-c-60-microsoft-cp1252
 hello

The culprit is loadfont(). This font[1] triggers XLoadQueryFont(), and
loadfont()
fails in the for loop. At least that's what my quick debug indicated.

I did a diff between dmenu 4.3.1 and 4.4.
Do we really want this twisted pretentious piece of code inside loadfont()?
I for one like the 4.3.1 code better. And it worked.

Patch attached inline. I do it the humble way.

[1] The font is MonteCarlo:
http://bok.net/MonteCarlo/downloads/MonteCarlo-PCF.tgz

--- dmenu-4.4-a/draw.c  2011-07-19 20:31:28.0 +
+++ dmenu-4.4-b/draw.c  2011-07-22 12:34:35.026736893 +
@@ -121,23 +121,25 @@ initfont(DC *dc, const char *fontstr) {
 Bool
 loadfont(DC *dc, const char *fontstr) {
char *def, **missing, **names;
-   int i, n = 1;
+   int i, n;
XFontStruct **xfonts;

if(!*fontstr)
return False;
-   if((dc-font.set = XCreateFontSet(dc-dpy, fontstr, missing, n, 
def)))
+   if((dc-font.set = XCreateFontSet(dc-dpy, fontstr, missing, n, 
def))) {
n = XFontsOfFontSet(dc-font.set, xfonts, names);
-   else if((dc-font.xfont = XLoadQueryFont(dc-dpy, fontstr)))
-   xfonts = dc-font.xfont;
-   else
-   n = 0;
-
-   for(i = 0; i  n; i++) {
-   dc-font.ascent  = MAX(dc-font.ascent,  xfonts[i]-ascent);
-   dc-font.descent = MAX(dc-font.descent, xfonts[i]-descent);
-   dc-font.width   = MAX(dc-font.width,   
xfonts[i]-max_bounds.width);
+   for(i = 0; i  n; i++) {
+   dc-font.ascent  = MAX(dc-font.ascent,  
xfonts[i]-ascent);
+   dc-font.descent = MAX(dc-font.descent, 
xfonts[i]-descent);
+   dc-font.width   = MAX(dc-font.width,   
xfonts[i]-max_bounds.width);
+   }
+   }
+   else if((dc-font.xfont = XLoadQueryFont(dc-dpy, fontstr))) {
+   dc-font.ascent  = dc-font.xfont-ascent;
+   dc-font.descent = dc-font.xfont-descent;
+   dc-font.width   = dc-font.xfont-max_bounds.width;
}
+
if(missing)
XFreeStringList(missing);
return (dc-font.set || dc-font.xfont);



[dev][dwm] Floating window center position fix

2011-07-20 Thread lolilolicon
I have a rule in config.h for MPlayer to always float. The bug was
observed when I played a 720p video whose window was 1280 pixels so it
filled the width of my laptop screen. The MPlayer window was supposed to
be centered, but a border line on the left was clearly visible. For
further confirmation, I set borderpx to 20. My observation was obviously
right. The patch is appended at the end.

Another thing I've observed but didn't care to fix when playing the video:
If the MPlayer window is always created in tag 4 (as per a rule), but I
run the mplayer command in xterm in tag 1, the visibility of the MPlayer
window border depends on some timing:

1) If I switch from tag 1 to tag 4 _after_ the MPlayer window is created,
   the border is visible.
2) If I switch from tag 1 to tag 4 _before_ the MPlayer window is created,
   the border is invisible. It seems for dwm the border exists, just not
   drawn. If I switch to another tag and back, or do a focusstack()
   using the default mod1+j combo or pretty about anything, the border
   will then be drawn.

Relevant entries in my test config.h are:

static const unsigned int borderpx = 20;
static const Rule rules[] = {
  { MPlayer, NULL, NULL, 1  3, True, -1 },
};

And following is my patch for the center position bug:

Patch for dwm 5.9
diff -up a/dwm.c b/dwm.c
--- a/dwm.c 1970-01-01 00:00:00.0 +
+++ b/dwm.c 1970-01-01 00:00:00.0 +
@@ -624,9 +624,9 @@ configurerequest(XEvent *e) {
if(ev-value_mask  CWHeight)
c-h = ev-height;
if((c-x + c-w)  m-mx + m-mw  c-isfloating)
-   c-x = m-mx + (m-mw / 2 - c-w / 2); /* 
center in x direction */
+   c-x = m-mx + (m-mw / 2 - WIDTH(c) / 2); /* 
center in x direction */
if((c-y + c-h)  m-my + m-mh  c-isfloating)
-   c-y = m-my + (m-mh / 2 - c-h / 2); /* 
center in y direction */
+   c-y = m-my + (m-mh / 2 - HEIGHT(c) / 2); /* 
center in y direction */
if((ev-value_mask  (CWX|CWY))  !(ev-value_mask  
(CWWidth|CWHeight)))
configure(c);
if(ISVISIBLE(c))